yda*_*niv 8 django django-models django-admin
我看到一些人在我之前有这个问题,但是在旧版本的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')
Run Code Online (Sandbox Code Playgroud)
每当我尝试在管理员中保存父级设置为"无"的类别时,如果有另一个具有相同名称且父级设置为"无"的类别,它仍然有效.
关于如何优雅地解决这个问题的想法?
Ala*_*air 10
在数据库级别强制执行唯一的约束约束,并且您的数据库引擎似乎不对空值应用约束.
在Django 1.2中,您可以为模型定义一个干净的方法来提供自定义验证.在您的情况下,只要父项为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 is None and Category.objects.filter(name=self.name, parent=None).exists():
raise ValidationError("Another Category with name=%s and no parent already exists" % self.name)
Run Code Online (Sandbox Code Playgroud)
如果您通过Django管理员编辑类别,将自动调用clean方法.在您自己的观点中,您必须致电category.fullclean().
我也遇到了这个问题,并通过创建一个带有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)
Run Code Online (Sandbox Code Playgroud)