这是问题所在:
我有这样的模型:
class UserBook(models.Model):
user = models.ForeignKey(User)
book = models.ForeignKey(Book)
is_active = models.BooleanField(default=False)
class Meta:
unique_together = ("user", "book")
显然,这个模型已经对现场用户和书籍有一个独特的约束约束。并且可能在数据库中会有这样的条目:
------------------------------
|user_id book_id is_active |
| 1 1 0 |
| 1 2 0 |
| 1 3 1 |
------------------------------
我还有一个要添加的约束,即每个用户最多只能有一个条目,即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)
添加字段键,并自定义此模型的保存方法。
但是在这种方法中max_length不能大于255(在我的情况下不需要担心,但有时候关键字段可能很长)。
所以,我想知道是否有更优雅的方法来解决这类问题。
谢谢!
重新定义is_active
如下:
# Equals user ID if active; otherwise null.
is_active = models.IntegerField(null = True, unique = True)
用户ID在列中是唯一的(满足您期望的约束),并且列中的许多空值不会违反约束,如here所讨论的。
在Django 2.2(目前作为beta1发布)你将能够使用UniqueConstraint,除了fields
列表可以通过condition
一个Q对象,指定您希望约束强制执行的条件。
例如,UniqueConstraint(fields = ['user'],condition = Q(status ='DRAFT')确保每个用户只有一个草稿。
您只需要在唯一约束中包含is_active
。
class UserBook(models.Model):
user = models.ForeignKey(User)
book = models.ForeignKey(Book)
is_active = models.BooleanField(default=False)
class Meta:
unique_together = ("user", "book", "is_active")
也就是说,我建议用户重新激活一本书,而不是使用非活动版本和活动版本。
旁注,请参阅many-to-many through以获得额外的好处(您可以将User.books
添加为多对多,使用UserBook
作为through
表)。