2010-08-22 90 views
4

我在Django以下模型:如何为Django Admin创建复杂的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?

回答

1

简短的回答:你可以在Django中使用“native django methods”来实现这一点。我不确定你的意思是什么“本地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的新混迹form validators

如果在另一方面你的用户可以创建使用API​​(比如,通过实例在其方案中Bout类)的情况下,那么你就必须通过覆盖Bout类的save()方法来做验证。

+0

干杯的响应。目前我只关心管理员的输入。 关于你的回答,这与我在与一位朋友交谈时提出的答案非常相似,尽管时间稍长。特别是,在您的方法中,您首先获取数据并将其复制到局部变量,然后返回cleared_data。 是否有任何理由选择不直接测试self.fighter_1,self.fighter_2,self.winer和self.date? – 2010-08-22 18:17:42

+0

我正在关注从'cleaned_data'属性中拾取数据而不是直接使用'self.field_name'的Django习惯用法。文档建议这是出于很好的理由:http://docs.djangoproject.com/en/dev/topics/forms/#processing-the-data-from-a-form – 2010-08-23 05:33:03

+0

干杯的解释性链接。 :-) – 2010-08-23 10:29:00

0

虽然马诺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.') 
+0

我需要纠正自己。第二次和第三次验证测试都应该开始: if(self.winner)and ...这样如果没有选择赢家,这些测试的其余部分不会执行。 (是的,我包括(self.winner)已经在第三次测试中,但是当我把它放在那里时它不能正常工作。当它在那里时,它实质上将赢家场变成必需场。 – 2010-08-23 04:57:08