Има ли някакъв по-елегантен начин за добавяне на чувствително към стойността уникално заедно ограничение в Django Model?

Ето го проблема:

Имам такъв модел:

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 при този подход (което не е причина да се притеснявате в моя случай, но понякога полето key може да е много дълго).

И така, бих искал да знам дали има някакъв по-елегантен подход за решаване на този вид проблем.

Благодаря!


person Johnny Zhao    schedule 10.05.2013    source източник


Отговори (3)


Предефинирайте is_active по следния начин:

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

Идентификаторите на потребителите ще бъдат уникални в колоната (задоволяват желаното от вас ограничение) и многото нулеви стойности в колоната няма да нарушат ограничението, както беше обсъдено тук.

person FMc    schedule 10.05.2013

В Django 2.2 (в момента пуснат като beta1) ще можете да използвате UniqueConstraint, което в допълнение към списъка от fields може да бъде предадено condition

Обект Q, който указва условието, което искате да наложи ограничението.

Например UniqueConstraint(fields=['user'], condition=Q(status='DRAFT') гарантира, че всеки потребител има само една чернова.

person Nour Wolf    schedule 15.03.2019

Въз основа на отговора на Nour можете да направите това:

class Meta:
    constraints = [
        models.UniqueConstraint(
            fields=['user'],
            condition=Q(is_active=True),
            name='unique active user book per user'
        ),
    ]
person Anthony    schedule 27.01.2020
comment
За съжаление получавам странна грешка could not create unique index 'unique user' as key(user, is_active)=(6,f) is duplicated. Настройвам is_active = True, но след това проверява и неактивни потребители. - person Pran Kumar Sarkar; 08.09.2020