本文是小编为大家收集整理的关于Django自定义唯一的一起约束的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。
问题描述
我有一个用户共享类似于以下的模型:
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)
此方法在正常使用中正常工作.
问题: 我有一个匹配的算法,该算法获得了共享的请求,并保存共享对象(s-r或r-s),然后将它们发送给他们响应(共享对象) 几乎同时 .当我使用查询(无数据库级别)检查重复时,这需要时间,所以最后我有2个对象S-R和R-S.
我想要一些解决方案,对于共享者s和a接收者r,我只能保存单个共享对象,s-r或r-s else否则会获得一些验证错误(例如databse的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 ,它可以用触发器解决此问题.
问题描述
I have a users share model something like below:
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") )
I want to save a single object for sharer(S) and receiver(R) (order doesn't matters R-S or S-R). but above unique_together will not fulfil this; Suppose R-S is in database and then if I save S-R I will not get validation for this. For this I have written custom unique validation for Share model.
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)
This method works fine in normal use.
Problem: I have an matching algorithm which gets a share's and a receiver's requests and saves Share object(either S-R or R-S) then send them response(share object) at almost same time. As I am checking duplication with query(no database level) it takes time, so at the end I have 2 Objects S-R and R-S.
I want some solution for this that for a sharer S and a receiver R I can only save single share object, either S-R or R-S else get some validation error(like IntegrityError of databse).
Django=1.4, Database=Postgresql
推荐答案
You probably could solve this with postgresql's indexes on expressions but here is another way:
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)
But it obviously wouldn't work if you change values with QuerySet.update method. You also could look at django-denorm, it solves this with triggers.