Python 如何跨外键验证唯一性约束(django)
我有以下(简化的)数据结构:Python 如何跨外键验证唯一性约束(django),python,django,django-models,Python,Django,Django Models,我有以下(简化的)数据结构: Site -> Zone -> Room -> name 我希望每个房间的名称对于每个站点都是唯一的 我知道,如果我只想让每个区域都独一无二,我可以: class Room(models.Model): zone = models.ForeignKey(Zone) name = models.CharField(max_length=255) class Meta: unique_to
Site
-> Zone
-> Room
-> name
我希望每个房间的名称对于每个站点都是唯一的
我知道,如果我只想让每个区域都独一无二,我可以:
class Room(models.Model):
zone = models.ForeignKey(Zone)
name = models.CharField(max_length=255)
class Meta:
unique_together = ('name', 'zone')
但我不能做我真正想做的事,那就是:
class Room(models.Model):
zone = models.ForeignKey(Zone)
name = models.CharField(max_length=255)
class Meta:
unique_together = ('name', 'zone__site')
我尝试添加一个validate_unique方法,如下所示:
但是我一定误解了validate_unique的要点/实现,因为在保存房间对象时没有调用它
执行此检查的正确方法是什么?保存模型时,不会单独调用方法。 一种方法是使用自定义保存方法,在保存模型时调用validate_unique方法:
class Room(models.Model):
zone = models.ForeignKey(Zone)
name = models.CharField(max_length=255)
def validate_unique(self, exclude=None):
qs = Room.objects.filter(name=self.name)
if qs.filter(zone__site=self.zone__site).exists():
raise ValidationError('Name must be unique per site')
def save(self, *args, **kwargs):
self.validate_unique()
super(Room, self).save(*args, **kwargs)
Django文档解释了包括此代码段在内的验证过程中涉及的步骤
请注意,调用模型的save()方法时,不会自动调用full_clean()
如果使用模型表单
创建模型实例,则验证表单时将进行验证
在如何处理验证方面有一些选项
full\u clean()
save()
方法,以便在每次保存时执行验证。您可以选择在此处进行多少验证,是要进行完全验证还是只进行唯一性检查
class Room(models.Model):
def save(self, *args, **kwargs):
self.full_clean()
super(Room, self).save(*args, **kwargs)
# In your models.py
from django.db.models.signals import pre_save
def validate_model_signal_handler(sender, **kwargs):
"""
Signal handler to validate a model before it is saved to database.
"""
# Ignore raw saves.
if not kwargs.get('raw', False):
kwargs['instance'].full_clean()
pre_save.connect(validate_model_signal_handler,
sender=Room,
dispatch_uid='validate_model_room')
我需要制作类似的程序。成功了。添加保存方法确实解决了我的问题,谢谢。不过,我很想知道何时会自动调用validate_unique。我读到的文档就好像它(和clean_x)是在保存模型实例时自动调用的,但这实际上只是在由于表单数据而进行编辑/保存时才调用的吗?是的,这些clean方法是在ModelForm中调用的。因此,在保存模型之前会进行自动验证。在您的情况下,保存模型时也会执行此操作。因此,即使用户在终端中保存模型而不是在表单中输入数据,也会进行验证。我想这是有道理的。当我没有显示任何表单的计划时,这并没有多大用处,但这是生活:真的。Django在调用
save()
方法时自动执行validate\u unique()
。@dragostis:我在方法中没有看到validate\u unique()
调用。因此,不,当您保存模型时,它不会自动执行:)如接受的答案中所述,您需要在覆盖的save
方法中调用它-save
默认情况下不调用validate\u unique。
# In your models.py
from django.db.models.signals import pre_save
def validate_model_signal_handler(sender, **kwargs):
"""
Signal handler to validate a model before it is saved to database.
"""
# Ignore raw saves.
if not kwargs.get('raw', False):
kwargs['instance'].full_clean()
pre_save.connect(validate_model_signal_handler,
sender=Room,
dispatch_uid='validate_model_room')
class Room(models.Model):
zone = models.ForeignKey(Zone)
name = models.CharField(max_length=255)
def validate_unique(self, *args, **kwargs):
super(Room, self).validate_unique(*args, **kwargs)
qs = Room.objects.filter(name=self.name)
if qs.filter(zone__site=self.zone__site).exists():
raise ValidationError({'name':['Name must be unique per site',]})