我看到一些人在我之前有这个问题,但是在旧版本的Django上,我正在运行1.2.1。
我的模型看起来像:
class Category(models.Model):
objects = CategoryManager()
name = models.CharField(max_length=30, blank=False, null=False)
parent = models.ForeignKey('self', null=True, blank=True, help_text=_('The direct parent category.'))
class Meta:
unique_together = ('name', 'parent')
每当我尝试在管理员中保存父级设置为“无”的类别时,当其他类别的SAME名称和父级设置为“无”时,它仍然有效。
关于如何优雅地解决这个问题的想法?
答案 0 :(得分:10)
在数据库级别强制实施唯一的约束,并且您的数据库引擎似乎不会对空值应用约束。
在Django 1.2中,您可以为模型定义clean method以提供自定义验证。在您的情况下,只要父级为None,您就需要检查具有相同名称的其他类别。
class Category(models.Model):
...
def clean(self):
"""
Checks that we do not create multiple categories with
no parent and the same name.
"""
from django.core.exceptions import ValidationError
if self.parent and Category.objects.filter(name=self.name).exists():
raise ValidationError("Another Category with name=%s and no parent already exists % self.name)
如果您通过Django管理员编辑类别,将自动调用clean方法。在您自己的观看中,您必须致电category.fullclean()
。
答案 1 :(得分:5)
我也遇到了这个问题并通过创建一个带有clean
方法的超模来解决它(就像Alasdair建议的那样)并将其用作我所有模型的基类:
class Base_model(models.Model):
class Meta:
abstract=True
def clean(self):
"""
Check for instances with null values in unique_together fields.
"""
from django.core.exceptions import ValidationError
super(Base_model, self).clean()
for field_tuple in self._meta.unique_together[:]:
unique_filter = {}
unique_fields = []
null_found = False
for field_name in field_tuple:
field_value = getattr(self, field_name)
if getattr(self, field_name) is None:
unique_filter['%s__isnull'%field_name] = True
null_found = True
else:
unique_filter['%s'%field_name] = field_value
unique_fields.append(field_name)
if null_found:
unique_queryset = self.__class__.objects.filter(**unique_filter)
if self.pk:
unique_queryset = unique_queryset.exclude(pk=self.pk)
if unique_queryset.exists():
msg = self.unique_error_message(self.__class__, tuple(unique_fields))
raise ValidationError(msg)
答案 2 :(得分:0)
不幸的是,对于那些使用PostgreSQL作为后端数据库引擎的人来说,永远不会有解决此问题的方法:
“当前,只有B树索引可以声明为唯一。
当索引被声明为唯一时,不允许具有相等索引值的多个表行。空值不视为相等。多列唯一索引只会拒绝多行中所有索引列均相等的情况。
在为表定义唯一约束或主键时,PostgreSQL自动创建唯一索引。该索引涵盖构成主键或唯一约束(如果适用的话,为多列索引)的列,并且是强制执行约束的机制。“