Django定制独特的约束

时间:2013-03-05 09:17:18

标签: database django validation postgresql unique-constraint

我有一个用户共享模型,如下所示:

class Share( models.Model ):
    sharer = models.ForeignKey(User, verbose_name=_("Sharer"), related_name='sharer')
    receiver = models.ForeignKey(User, verbose_name=_("Receiver"), related_name='receiver')

    class Meta:
        unique_together = ( ("sharer", "receiver"), ("receiver", "sharer") )

我想为sharer(S)和receiver(R)保存单个对象(顺序与R-S或S-R无关)。但以上unique_together将无法满足此要求;假设R-S在数据库中,然后如果我保存S-R,我将不会得到验证。为此,我为Share模型编写了自定义唯一验证。

    def validate_unique(
        self, *args, **kwargs):
            super(Share, self).validate_unique(*args, **kwargs)
            if self.__class__.objects.filter( Q(sharer=self.receiver, receiver=self.sharer) ).exists():
                raise ValidationError(
                    {
                        NON_FIELD_ERRORS:
                        ('Share with same sharer and receiver already exists.',)
                    }
                )

    def save(self, *args, **kwargs):
        # custom unique validate
        self.validate_unique()
        super(Share, self).save(*args, **kwargs)

此方法在正常使用中正常工作。

问题: 我有一个匹配算法,它获取共享和接收者的请求并保存共享对象(S-R或R-S),然后几乎同时向他们发送响应(共享对象) 。因为我正在检查与查询的重复(没有数据库级别)需要时间,所以最后我有2个对象S-R和R-S。

我想要一些解决方案,对于共享者S和接收者R我只能保存单个共享对象,S-R或R-S否则会得到一些验证错误(如数据库的IntegrityError)。

Django = 1.4,Database = Postgresql

1 个答案:

答案 0 :(得分:4)

您可能可以使用postgresql的indexes on expressions来解决这个问题,但这是另一种方式:

class Share( models.Model ):
    sharer = models.ForeignKey(User)
    receiver = models.ForeignKey(User), related_name='receiver')
    key = models.CharField(max_length=64, unique=True)

    def save(self, *args, **kwargs):
        self.key = "{}.{}".format(*sorted([self.sharer_id, self.receiver_id]))
        super(Share, self).save(*args, **kwargs)

但是如果使用QuerySet.update方法更改值,它显然不起作用。您还可以查看django-denorm,它通过触发器解决了这个问题。