如何为 Django Admin 创建复杂的 Django 模型验证?

发布于 2024-09-15 02:38:05 字数 715 浏览 9 评论 0原文

我在 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 不同(这仅适用于 monty python 短剧)。

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

  3. 之前不能设置获胜者比赛进行。 (毕竟,这不是 WWE。)

所有这三个规则都要求将同一记录中的一个字段与另一个字段进行检查。是否可以在 django 中使用本机 django 方法或求助于 python 来执行此操作?

I have the following model in 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()

I would like to "idiot-proof" the administration for its records. Incidently, I want to create three rules:

  1. Fighter 1 is not the same as fighter 2 (which is only good for a monty python skit).

  2. Winner should be in the bout (i.e., either Fighter 1 or Fighter 2)

  3. The winner can't be set before the match takes place. (After all, this isn't WWE.)

All three of these rules require checking one field against another field in the same record. Is it possible to do this in django, either using native django methods or resorting to python?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

扭转时空 2024-09-22 02:38:05

简短的回答:您可以在 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

上面的片段不完整。您可以对其进行调整以满足您的需求。还可以看看 Django 的新的表单验证器

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

Short answer: you can achieve this in Django using "native django methods". I am not sure what exactly you mean by "native Django methods"; I am assuming that you mean making calls to the Django API.

There are a couple of ways to go about this. If your users can only create Bout instances using a form that you provide then the form's validation methods can test for the conditions you mentioned. For e.g.:

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

The above snippet is incomplete. You can tweak it to meet your needs. Also take a look at Django's new fangled form validators.

If on the other hand your users can create instances using the API (say, by instantiating the Bout class in their programs) then you'll have to do the validation by overriding the save() method of the Bout class.

最佳男配角 2024-09-22 02:38:05

虽然 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.')

While Manoj Govindan's answer looks very good, I also came up with my own solution... I'll include it here in case anyone finds my slightly shorter solution preferable:

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.')
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文