21

我有以下(简化的)数据结构:

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 方法:

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')

        models.Model.validate_unique(self, exclude=exclude)

但我一定误解了 validate_unique 的要点/实现,因为当我保存 Room 对象时它没有被调用。

实施此检查的正确方法是什么?

4

3 回答 3

20

保存模型时不会自行调用方法。一种方法是使用自定义保存方法,该方法在保存模型时调用 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)
于 2013-01-23T01:25:24.427 回答
8
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',]})

我需要制作类似的程序。有效。

于 2015-02-27T11:33:22.977 回答
6

Django Validation objects文档解释了验证中涉及的步骤,包括这个片段

请注意,调用模型的 save() 方法时不会自动调用 full_clean()

如果模型实例是由于使用 a 而创建的ModelForm,则验证将在验证表单时进行。

在如何处理验证方面有一些选择。

  1. full_clean()在保存之前手动调用模型实例。
  2. 覆盖save()模型的方法以在每次保存时执行验证。您可以在此处选择应进行多少验证,无论您想要完全验证还是仅进行唯一性检查。

    class Room(models.Model):
        def save(self, *args, **kwargs):
            self.full_clean()
            super(Room, self).save(*args, **kwargs)
    
  3. 使用 Django pre_save信号处理程序,它将在保存之前自动执行验证。这提供了一种非常简单的方法来在现有模型上添加验证,而无需任何额外的模型代码。

    # 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')
    
于 2013-01-23T04:11:26.483 回答