5

这是问题所在:

我有一个这样的模型:

class UserBook(models.Model):
    user = models.ForeignKey(User)
    book = models.ForeignKey(Book)
    is_active = models.BooleanField(default=False)

    class Meta:
        unique_together = ("user", "book")

显然,该模型已经对 field userbook具有唯一的共同约束。并且可能在数据库中会有一些这样的条目:

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

添加一个字段key,并自定义该模型的保存方法。

但是在这种方法中max_length不能大于 255(在我的情况下无需担心,但有时关键字段可能很长)。

所以,我想知道是否有更优雅的方法来解决这类问题。

谢谢!

4

3 回答 3

7

Django 2.2(目前作为 beta1 发布)中,您将能够使用UniqueConstraint,除了fields可以传递的列表之外condition

一个Q对象,它指定您希望约束强制执行的条件。

例如,UniqueConstraint(fields=['user'], condition=Q(status='DRAFT')确保每个用户只有一个草稿。

于 2019-03-15T10:56:15.720 回答
6

根据 Nour 的回答,您可以这样做:

class Meta:
    constraints = [
        models.UniqueConstraint(
            fields=['user'],
            condition=Q(is_active=True),
            name='unique active user book per user'
        ),
    ]
于 2020-01-27T22:11:14.670 回答
2

重新定义is_active如下:

# Equals user ID if active; otherwise null.
is_active = models.IntegerField(null = True, unique = True)

用户 ID 在列中将是唯一的(满足您​​所需的约束),并且列中的许多空值不会违反约束,如此所述。

于 2013-05-10T03:53:51.650 回答