Django自定义唯一共同约束

2024-01-24

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

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

我想为共享者(S)和接收者(R)保存一个对象(顺序并不重要,R-S 或 S-R)。但上面的 unique_together 无法实现这一点;假设 R-S 在数据库中,然后如果我保存 S-R,我将不会得到对此的验证。为此,我为共享模型编写了自定义唯一验证。

    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)

这种方法在正常使用中效果很好。

Problem:我有一个匹配算法,它获取共享和接收者的请求并保存共享对象(S-R 或 R-S),然后向它们发送响应(共享对象)几乎同时。当我使用查询检查重复项(无数据库级别)时,这需要时间,所以最后我有 2 个对象 S-R 和 R-S。

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

Django=1.4,数据库=Postgresql


你也许可以用 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 https://github.com/initcrash/django-denorm,它通过触发器解决了这个问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django自定义唯一共同约束 的相关文章

随机推荐