Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/283.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何跨外键验证唯一性约束(django)_Python_Django_Django Models - Fatal编程技术网

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)
    
  • 使用Django信号处理程序,它将在保存前自动执行验证。这提供了一种非常简单的方法,可以在现有模型上添加验证,而无需任何其他模型代码

    # 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',]})