关于python:有没有更优雅的方法在Django模型中添加一个值敏感的唯一一起约束?

Is there any more elegant way to add a value sensitive unique together constraint in Django Model?

问题是:

我有一个这样的模型:

1
2
3
4
5
6
7
class UserBook(models.Model):
    user = models.ForeignKey(User)
    book = models.ForeignKey(Book)
    is_active = models.BooleanField(default=False)

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

显然,这个模型已经为现场用户和图书提供了一个独特的together约束。数据库中可能会有这样的条目:

1
2
3
4
5
6
    ------------------------------
    |user_id  book_id  is_active |
    |      1        1          0 |
    |      1        2          0 |
    |      1        3          1 |
    ------------------------------

我还有一个要添加的约束,即每个用户最多可以有一个条目,is_active字段的值为1(true)。

目前,我通过将模型改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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)

添加字段键,并自定义此模型的保存方法。

但在这种方法中,最大长度不能大于255(在我的例子中不需要担心,但有时键字段可能很长)。

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

谢谢!


is_active重新定义为:

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

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


在Django 2.2(目前发布为beta1)中,您将能够使用唯一约束,除了fields的列表外,还可以传递condition

A Q object that specifies the condition you want the constraint to enforce.

For example, UniqueConstraint(fields=['user'], condition=Q(status='DRAFT') ensures that each user only has one draft.


您只需要在唯一约束中包含is_active

1
2
3
4
5
6
7
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")

也就是说,我建议让用户重新激活一本书,而不是让用户拥有一个不活动和活动的版本。

旁注:为了一些额外的好处,从多到多看(你可以把User.books加为多到多,用你的UserBook作为through表)。