Skip to main content
 首页 » 编程设计

python之ManyToMany 字段上的 Django-admin 验证

2025年04月02日42mq0036

我有一个 Django 模型,其中有一个模块类,可以将字段“排序”设置为 4 个值(视频、文章、测验、测试)之一。如果选择了视频或文章,那么我会进行验证以确保字段“文本文件”(这是一个上传的文件)不为空。我想验证如果选择了测验或测试,那么至少还会添加一个问题。您可以在下面的类模块中看到我尝试的验证,但它不起作用。

这是models.py:

class Question(models.Model): 
    name = models.CharField(max_length=500, verbose_name="Question") 
    QUESTION_TYPE = ( 
        ('Multi', 'Multiple Choice (one correct answer)'), 
        ('Check', 'Multiple Answers'), 
        ('Matched', 'Match Responses on left with answers on right'), 
    ) 
    sort = models.CharField( 
        default="Multi", 
        max_length=7, 
        verbose_name = "Question Type", 
        choices = QUESTION_TYPE) 
    answer = models.ManyToManyField( 
        Answer, 
        through         = 'QuestionAnswer', 
        related_name    = 'answer', 
        verbose_name    = 'Answer', 
        help_text       = 'Answers to this Question' 
        ) 
 
    def __unicode__(self): 
        return u'%s' % (self.name) 
 
 
class Module(models.Model): 
    name = models.CharField(verbose_name='Module Title', max_length=50) 
    MODULE_TYPE = ( 
        ('Video', 'Video'), 
        ('Quiz', 'Quiz'), 
        ('Article', 'Article'), 
        ('Test','Test') 
    ) 
    sort = models.CharField( 
        verbose_name='Module Content', 
        default="Video", 
        max_length=7, 
        choices = MODULE_TYPE) 
    textfile = models.ForeignKey(DataFile, blank=True, null=True, verbose_name='Data File' ) 
    description = models.TextField(blank=True, null=True, verbose_name='Module Description')     
    weight = models.IntegerField(default=0, verbose_name="Module Weighting", help_text="Provide the weight you want this module to carry in the course final score.") 
    question = models.ManyToManyField( 
        Question, 
        through         = 'ModuleQuestions', 
        related_name    = 'question', 
        verbose_name    = 'Question', 
        help_text       = 'Questions in this Module' 
        ) 
 
    def __unicode__(self): 
        return u'%s' % (self.name) 
 
    def clean (self): 
        if self.sort in ['Video','Article']: 
            if not self.textfile: 
                 raise ValidationError( 
                    _("Videos and Articles must have an linked Data File"), 
                    ) 
        if self.sort in ['Quiz','Test']: 
            if not self.question : 
                raise ValidationError ( 
                    _("Quiz and Test Modules must have at least 1 Question"), 
                ) 
 
class ModuleQuestions(models.Model): 
    module = models.ForeignKey( 
        Module, 
        verbose_name    = 'Module', 
        help_text       = 'Module is part of a Course.', 
    ) 
    question = models.ForeignKey( 
        Question, 
        verbose_name    = 'Question', 
        help_text       = 'Quiz and Test Modules have Questions allocated to them.', 
    )        
    order = models.IntegerField( 
        verbose_name    = 'Order', 
        help_text       = 'The order the Questions are presented to the student', 
    ) 

这是我的 admin.py

class ModuleQuestionsInline(admin.TabularInline): 
    model = ModuleQuestions 
    extra = 1 
 
class ModuleAdmin(admin.ModelAdmin): 
    inlines = (ModuleQuestionsInline,) 
 
class QuestionAnswerInline(admin.TabularInline): 
    model = QuestionAnswer 
    extra = 1 
 
 
class QuestionAdmin(admin.ModelAdmin): 
    inlines = (QuestionAnswerInline,) 
 
 
admin.site.register(Module, ModuleAdmin) 
admin.site.register(Question, QuestionAdmin) 

任何帮助将不胜感激。

请您参考如下方法:

https://groups.google.com/d/msg/django-users/f_MKyPg_C4w/0WMJol1atOoJ

Basically, you can't. M2m fields are saved after the model is saved, so you either get objects that are not yet ready for that check (as you experienced) or you will test the previous value of the m2m field, neither of which is what you want.

You can modify the admin interface and do the validation in the AdminForm, or perhaps catch the m2m_changed signal and do some checks there, but you can't do the validation you want in the clean method.