【问题标题】:How can I create sophisticated Django Model Validation for Django Admin?如何为 Django Admin 创建复杂的 Django 模型验证?
【发布时间】:2011-04-02 06:08:53
【问题描述】:

我在 Django 中有以下模型:

class Bout (models.Model):
    fighter_1 = models.ForeignKey(Fighter, related_name="bout_fighter_1")
    fighter_2 = models.ForeignKey(Fighter, related_name="bout_fighter_2")
    winner = models.ForeignKey(Fighter, related_name="bout_winner", 
        blank=True, null=True, help_text='Leave blank for draw.') 
    date = models.DateField()
    cancelled = models.BooleanField()

我想“防止白痴”管理部门的记录。顺便说一句,我想创建三个规则:

  1. 战斗机 1 与战斗机 2 不同(这只适用于巨蟒短剧)。

  2. 获胜者应该在比赛中(即战斗机 1 或战斗机 2)

  3. 在比赛开始前无法确定获胜者。 (毕竟,这不是 WWE。)

所有这三个规则都要求检查同一记录中的一个字段与另一个字段。是否可以在 django 中做到这一点,无论是使用原生 django 方法还是求助于 python?

【问题讨论】:

    标签: django django-models django-admin django-validation


    【解决方案1】:

    简短回答:您可以在 Django 中使用“原生 django 方法”来实现这一点。我不确定您所说的“本机 Django 方法”到底是什么意思;我假设您的意思是调用 Django API。

    有几种方法可以解决这个问题。如果您的用户只能使用您提供的表单创建 Bout 实例,那么表单的验证方法可以测试您提到的条件。例如:

    class BoutForm(forms.ModelForm):
        class Meta:
            model = Bout
    
        def clean(self):
            fighter_1 = self.cleaned_data.get('fighter_1')
            fighter_2 = self.cleaned_data.get('fighter_2')
            winner = self.cleaned_data.get('winner')  
            date = self.cleaned_data.get('date')
    
            if not (fighter_1 and fighter_2 and (fighter_1.id != fighter_2)):
                raise forms.ValidationError("Both fighters cannot be the same")
    
            if not (winner and (winner.id == fighter_1.id or winner.id == fighter_2.id)):
                raise forms.ValidationError("Winner is not in the fight")
    
            if not (date and date < datetime.today()):
                raise forms.ValidationError("Winner is not in the fight")
    
            return self.cleaned_data
    

    上面的sn-p是不完整的。您可以对其进行调整以满足您的需求。还可以看看 Django 新奇的form validators

    另一方面,如果您的用户可以使用 API 创建实例(例如,通过在他们的程序中实例化 Bout 类),那么您必须通过覆盖 @987654327 的 save() 方法来进行验证@类。

    【讨论】:

    • 为响应干杯。目前我只关心来自管理员的输入。关于您的回答,这与我与朋友交谈时得出的答案非常相似,尽管稍长一些。特别是,在您的方法中,您首先获取数据并将其复制到局部变量,然后返回clean_data。您有什么理由选择不直接测试 self.fighter_1、self.fighter_2、self.winer 和 self.date?
    • 我遵循 Django 习惯,从cleaned_data 属性中获取数据,而不是直接使用self.field_name。文档建议这样做是有充分理由的:docs.djangoproject.com/en/dev/topics/forms/…
    • 为解释性链接干杯。 :-)
    【解决方案2】:

    虽然 Manoj Govindan 的回答看起来非常好,但我也想出了自己的解决方案……我会在此处包含它,以防有人觉得我的略短的解决方案更可取:

    def clean(self):
        if self.fighter_1 == self.fighter_2:
            raise ValidationError('Fighter 1 can not be Fighter 2.')
        if (self.winner != self.fighter_1) and (self.winner != self.fighter_2):
            raise ValidationError('Winner must be in the bout.')
        if (self.date >= datetime.date.today()) and (self.winner):
            raise ValidationError('Winner can not be set before match.')
    

    【讨论】:

    • 我需要纠正自己。第二个和第三个验证测试都应该开始: if (self.winner) 和 ... 如果没有选择获胜者,其余的这些测试就不会被执行。 (是的,我已经在第三次测试中包含了(self.winner),但是当我把它放在那里时它不能正常工作。当它在那里时,它实际上将获胜者字段变成了必填字段。
    猜你喜欢
    • 2012-10-15
    • 1970-01-01
    • 1970-01-01
    • 2017-03-04
    • 2020-10-12
    • 2020-04-04
    • 2017-08-16
    • 2011-10-04
    • 1970-01-01
    相关资源
    最近更新 更多