Django: 'unique_together' and 'blank=True'
我有一个Django模型,看起来像这样:
1 2 3 4 5 6 7 | class MyModel(models.Model): parent = models.ForeignKey(ParentModel) name = models.CharField(blank=True, max_length=200) ... other fields ... class Meta: unique_together = ("name","parent") |
这是正常的;如果同一个
但是,当我用同一个
首先,空白(空字符串)与空(
其次,当通过表单使用django charfield时,当您将字段留空时,将存储空字符串。
所以,如果你的字段不是charfield,你应该在其中添加
1 2 3 4 5 6 | class NullCharField(forms.CharField): def clean(self, value): value = super(NullCharField, self).clean(value) if value in forms.fields.EMPTY_VALUES: return None return value |
。
然后在模型窗体中使用它:
1 2 | class MyModelForm(forms.ModelForm): name = NullCharField(required=False, ...) |
这样,如果您将其留空,它将在数据库中存储空值而不是空字符串(
使用
这在数据库级别使用相应数据库列上的
相反,您可以通过在模型上覆盖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class MyModel(models.Model): ... def save(self, *args, **kwargs): if self.name != '': conflicting_instance = MyModel.objects.filter(parent=self.parent, \ name=self.name) if self.id: # This instance has already been saved. So we need to filter out # this instance from our results. conflicting_instance = conflicting_instance.exclude(pk=self.id) if conflicting_instance.exists(): raise Exception('MyModel with this name and parent already exists.') super(MyModel, self).save(*args, **kwargs) |
希望有帮助。
这个解决方案与@bigmattyh给出的解决方案非常相似,但是,我发现下面的页面描述了应该在哪里进行验证:
http://docs.djangoproject.com/en/1.3/ref/models/instances/验证对象
我最终使用的解决方案如下:
1 2 3 4 5 6 7 8 9 10 11 | from django import forms class MyModel(models.Model): ... def clean(self): if self.name != '': instance_exists = MyModel.objects.filter(parent=self.parent, name=self.name).exists() if instance_exists: raise forms.ValidationError('MyModel with this name and parent already exists.') |
。
请注意,将引发validationError而不是一般异常。此解决方案的好处是,当使用.is valid()验证模型窗体时,将自动调用上面的models.clean()方法,并将validationError字符串保存在.errors中,以便在HTML模板中显示。
如果你不同意这个解决方案,请告诉我。
Bigmatthy很好地解释了正在发生的事情。我将添加一个可能的
1 2 3 4 | def save(self, *args, **kwargs): if self.parent != None and MyModels.objects.filter(parent=self.parent, name=self.name).exists(): raise Exception('MyModel with this name and parent exists.') super(MyModel, self).save(*args, **kwargs) |
号
我想我选择了通过覆盖我的模型的clean方法来做类似的事情,它看起来是这样的:
1 2 3 4 | from django.core.exceptions import ValidationError def clean(self): if self.parent != None and MyModels.objects.filter(parent=self.parent, name=self.name).exists(): raise ValidationError('MyModel with this name and parent exists.') |