Как я могу обновить django BooleanField с помощью логической комбинации других BooleanField на той же модели? - PullRequest
0 голосов
/ 09 ноября 2018

Рассмотрим эту простую модель django (при поддержке Postgres):

class M(Model):
    a = BooleanField(default=False)
    b = BooleanField(default=False)
    c = BooleanField(default=False)

    class Meta:
        app_label = 'my_app'

Как я могу использовать update для установки значения c на логическое И * a и b? Мой первый инстинкт был

M.objects.update(c=F('a') and F('b'))

но, по-видимому, сначала выполняется питон (с логическим AND функций F, просто возвращающих второй метод), потому что это приводит к следующему SQL:

UPDATE "my_app_m"
SET "c" = "my_app_m"."b"

Я попытался обернуть выражение в ExpressionWrapper, но это не дало эффекта. Я также попытался использовать * вместо and (для умножения выражений F), но это привело к ошибке операции на стороне sql.

Я знаю, что мог бы сделать это в python, извлекая объекты, манипулируя ими, а затем сохраняя. Я предполагаю, что я мог бы также сделать обновление, приведя к int, затем умножив, затем приведя обратно. Но я удивлен, что ORM не просто справляется с этим. Есть ли шаг, который я пропускаю, или другой стандартный способ достижения того же эффекта?

Спасибо за ваше время!

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Вы можете использовать Q объект здесь:

from django.db.models import <b>Q</b>

M.objects.update(c=<b>Q(a=True, b=True)</b>)

В PostgreSQL это приведет к запросу:

UPDATE "my_app_m"
SET "c" = ("my_app_m"."a" = true AND "my_app_m"."b" = true)
0 голосов
/ 09 ноября 2018

Немного покопавшись, я нашел это решение. Не большой поклонник отвечать на мои собственные вопросы, но это меня раздражало, так что, возможно, это поможет кому-то еще. Я не уверен, что это лучшее или самое прямое решение, так что, надеюсь, кто-то еще придумает лучший ответ, и я могу принять это.

Что у меня сейчас есть:

    M.objects.update(
        c=Case(
            When(a=True, b=True, then=Value(True)),
            default=Value(False)
        )
    )

Еще одна альтернатива. Думаю, это должно было быть очевидно, учитывая природу этой конкретной проблемы, но мне никогда не приходит в голову выбрать больше запросов:

    M.objects.update(c=False)
    M.objects.filter(a=True, b=True).update(c=True)
...