如何使用模型属性验证Django表单?

时间:2013-09-10 15:06:34

标签: django forms validation

我有一个Django模型(ChildrenGodfather),涉及其他3个模型:Child,Godfather和Edition(2012,2013,2014 ..)。

当我们创建一个新的ChildrenGodfather时,没有Edition字段:它会自动使用最新版本保存它,而不会向用户显示(已经工作)

我们不能在同一版本中拥有相同教父的同一个孩子,但我们可以在不同的版本中拥有相同教父的同一个孩子。

问题是..创建时表单中没有字段版本,所以我们没有办法验证版本。所以我们的验证不允许我们在不同的版本中让Child与同一个教父。

您可以在此处获得有效的代码:

==== models.py ====

class Edition(models.Model):
    name = models.CharField(max_length=255, verbose_name=u'Name')
    date = models.DateField(verbose_name=u'Date')

class Godfather(models.Model):
    name = models.CharField(max_length=255, verbose_name=u'Name')
    is_active = models.BooleanField(_('active'), default=True, help_text=u'Is active?')

class Children(models.Model):
    name = models.CharField(max_length=255, verbose_name=u'Name')
    is_active = models.BooleanField(_('active'), default=True, help_text=u'Is active?')

class ChildrenGodfather(models.Model):
    class Meta:
        verbose_name = u'Sponsorship'
        unique_together = ['child', 'godfather', 'edition']

    child = models.ForeignKey(Children, verbose_name=u'Child')
    godfather = models.ForeignKey(Godfather, verbose_name=u'Godfather')
    edition = models.ForeignKey(Edition)

    def save(self, *args, **kwargs):
        # if it is creating, don t need to tell edition
        if not self.pk:
            self.edition = Edition.objects.order_by('-date')[0:1].get()
        super(ChildrenGodfather, self).save(*args, **kwargs)

==== forms.py ====

class ChildrenGodfatherForm(forms.ModelForm):
    child = forms.ModelChoiceField(label=u'Child', queryset=Children.objects.filter(is_active=True))
    godfather = forms.ModelChoiceField(label=u'Godfather', queryset=Godfather.objects.filter(is_active=True))

    # TODO improve checking for editions
    def clean(self):
        try:
           ChildrenGodfather.objects.get(child=self.cleaned_data['child'], 
                                         godfather=self.cleaned_data['godfather'])     
            #if we get this far, we have an exact match for this form's data
            raise forms.ValidationError(u"This sponsorship already exists. Duplicated sponsorship are not allowed!")
        except ChildrenGodfather.DoesNotExist:
            #because we didn't get a match
            pass
        return self.cleaned_data

==== admin.py ====

class ChildrenGodfatherAdmin(admin.ModelAdmin):
    form = ChildrenGodfatherForm
    fields = ['child', 'godfather']
    list_display = ['__unicode__', 'child', 'godfather', 'status']
    list_filter = ['child', 'godfather', 'status']

感谢。

2 个答案:

答案 0 :(得分:1)

您可以覆盖ChildrenGodfatherForm的 init 方法来初始化默认版

def __init__(self, *args, **kwargs):
    super(ChildrenGodfatherForm, self).__init__(*args,**kwargs)
    instance = kwargs.get('instance')
    if instance is not None:
        self.edition = instance.edition  # updating existing object, use its edition
    else:            
        self.edition = Edition.objects.latest('date') # creating new object, use default edition.

然后在clean方法中修改查询以使用此参数

ChildrenGodfather.objects.get(child=self.cleaned_data['child'], 
                             godfather=self.cleaned_data['godfather'], edition=self.edition)     

答案 1 :(得分:1)

def default_edition():
    return Edition.objects.latest('date') # or Edition.objects.order_by('-date')[0]

class ChildrenGodfather(models.Model):
    class Meta:
        verbose_name = u'Sponsorship'
        unique_together = ['child', 'godfather', 'edition']

    child = models.ForeignKey(Children, verbose_name=u'Child')
    godfather = models.ForeignKey(Godfather, verbose_name=u'Godfather')
    edition = models.ForeignKey(Edition, default=default_edition)

    def save(self, *args, **kwargs):
        super(ChildrenGodfather, self).save(*args, **kwargs)

class ChildrenGodfatherAdmin(admin.ModelAdmin):
    form = ChildrenGodfatherForm
    fields = ['child', 'godfather', 'edition']
    list_display = ['__unicode__', 'child', 'godfather', 'edition', 'status']
    list_filter = ['child', 'godfather', 'edition', 'status']

如果您希望在创建对象时隐藏版本字段,但在对象版本上可见,则可以将此方法添加到ChildrenGodfatherAdmin类:

def get_form(self, request, obj=None, **kwargs):
    if obj is None:
        self.exclude = ["edition"]
    form = super(ChildrenGodfatherAdmin, self).get_form(request, obj, **kwargs)
    return form