![](/img/trans.png)
[英]Django: Is there a way to add a foreign key field to “unique_together”?
[英]Django: unique_together for foreign field
对于接下来的两个模型:
class Foo(models.Model):
parent = models.ForeignKey(Parent)
name = models.CharField()
class Bar(models.Model):
foreign = models.ForeignKey(Foo)
value = models.CharField(max_length=20)
我需要对Bar
模型具有unique_together约束:
class Meta:
unique_together = ('value', 'foreign__parent')
在Django中这是不可能的。
但是是否有可能在数据库级别(Postgresql)上通过某些约束或模型级别验证来实现这一点,从而在将相同的value
同时保存到不同的Bar
实例时省略可能的情况(锁定表?)?
的Django 2.2.4
您无法使用unique_together
实现它,因为它会在数据库级别创建索引。 但是,您可以自己添加验证,只需覆盖validate_unique
方法并将此验证添加到其中即可。
from django.core.exceptions import ValidationError
class Bar(models.Model):
foreign = models.ForeignKey(Foo)
value = models.CharField(max_length=20)
def validate_unique(self, *args, **kwargs):
super(MyModel, self).validate_unique(*args, **kwargs)
if self.__class__.objects.\
filter(foreign__parent=self.foreign.parent, vaue=self.value).exists():
raise ValidationError(
message='record already exists with given values.',
code='unique_together',
)
感谢Anjaneyulu Batta ,提出了下一个解决方案:
@contextmanager
def lock_table(model):
"""
Lock target table on commands UPDATE, DELETE and INSERT
"""
with transaction.atomic(), transaction.get_connection().cursor() as cursor:
cursor.execute(
f'LOCK TABLE {model._meta.db_table} IN ROW EXCLUSIVE MODE;'
)
yield
对于模型:
def validate_unique(self, exclude=None):
super().validate_unique(exclude)
queryset = type(self).objects.filter(
value=self.value,
foreign__parent=self.foreign.parent,
)
if self.pk:
queryset = queryset.exclude(pk=self.pk)
if queryset.exists():
raise IntegrityError(_('Value must be unique for foreign field'))
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
with lock_table(type(self)):
self.validate_unique()
super().save(force_insert, force_update, using, update_fields)
应该可以正常保存。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.