Joh*_*hao 4 python django django-models django-database
问题是这样的:
我有一个这样的模型:
class UserBook(models.Model):
user = models.ForeignKey(User)
book = models.ForeignKey(Book)
is_active = models.BooleanField(default=False)
class Meta:
unique_together = ("user", "book")
Run Code Online (Sandbox Code Playgroud)
显然,这个模型已经对现场用户和书籍有了独特的共同约束。数据库中可能会有一些这样的条目:
------------------------------
|user_id book_id is_active |
| 1 1 0 |
| 1 2 0 |
| 1 3 1 |
------------------------------
Run Code Online (Sandbox Code Playgroud)
我还要添加一个约束,即每个用户最多可以拥有一个is_active字段值为 1(True) 的条目。
目前我通过将模型更改为这样来解决这个问题:
class UserBook(models.Model):
user = models.ForeignKey(User)
book = models.ForeignKey(Book)
is_active = models.BooleanField(default=False)
key = models.charFeild(max_length=255, unique=True)
class Meta:
unique_together = ("user", "book")
def save(self, *args, **kwargs):
if self.is_active:
self.key = "%s_%s" %(self.user_id, self.is_active)
else:
self.key = "%s_%s_%s" %(self.user_id, self.is_active, self.book_id)
Run Code Online (Sandbox Code Playgroud)
添加字段key,并自定义该模型的保存方法。
但这种方法中max_length不能大于 255(在我的情况下无需担心,但有时关键字段可能会很长)。
所以,我想知道是否有更优雅的方法来解决此类问题。
谢谢!
在Django 2.2(目前作为 beta1 发布)中,您将能够使用UniqueConstraint,除了fields可以传递的列表之外condition
一个Q对象,指定您希望约束强制执行的条件。
例如,UniqueConstraint(fields=['user'], condition=Q(status='DRAFT')确保每个用户只有一个草稿。
根据Nour的回答,你可以这样做:
class Meta:
constraints = [
models.UniqueConstraint(
fields=['user'],
condition=Q(is_active=True),
name='unique active user book per user'
),
]
Run Code Online (Sandbox Code Playgroud)
重新定义is_active如下:
# Equals user ID if active; otherwise null.
is_active = models.IntegerField(null = True, unique = True)
Run Code Online (Sandbox Code Playgroud)
用户 ID 在列中是唯一的(满足您所需的约束),并且列中的许多空值不会违反约束,如此处所述。