Получение дополнительного поля через аннотацию в отношении "многие ко многим" в Django

У меня есть m2m связь между моделью Feature и моделью User через промежуточную таблицу. Модель функций представляет все доступные функции, и пользователь может включить или отключить ноль, одну или несколько из них через web или api. Когда пользователь включает функцию, в промежуточной таблице создается соответствующая запись, когда пользователь отключает функцию, запись удаляется.

from django.contrib.auth.models import User

class Feature(models.Model):
    name = models.CharField(max_length=50)
    user = models.ManyToManyField(User, through='FeatureUserM2M')
    ...other fields...

class FeatureUserM2M(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    feature = models.ForeignKey(Feature, on_delete=models.CASCADE)
    ...other fields...

Предлагаем данные таким образом

Feature            User          Intermediary
|id|name        |  |id|name   |  |id|user_id|feature_id|
+--+------------+  +--+-------+  +--+-------+----------+
|1 |feature foo |  |1 |user A |  |1 |2      |1         |
|2 |feature bar |  |2 |user B |  |  |       |          |
|3 |feature baz |  |  |       |  |  |       |          |

Мне нужен результат со всеми доступными функциями, а для данного пользователя еще одно поле, указывающее, включена ли у пользователя эта функция или нет (может быть булево значение). В идеале, для "пользователя A" результат должен быть следующим:

|user_id|feature_id|enabled |
+-------+----------+--------+
|2      |1         | true   |
|2      |2         | false  |
|2      |3         | false  |

Я пытался

Feature.objects.annotate(enabled=Subquery(
    FeatureUserM2M.objects.filter(
        feature=OuterRef('pk'),
        user=request.user,
    )
))
*** django.core.exceptions.FieldError: Cannot resolve expression type, unknown output_field

Я не думаю, что запрос, который я сделал, правильный, но даже указав тип вывода как BooleanField я не получаю того, что хочу.

*** TypeError: QuerySet.annotate() received non-expression(s): <class 'django.db.models.fields.BooleanField'>.

Похоже, что вы можете просто использовать подзапрос Exists(). Пример и описание этого есть в документации здесь:

https://docs.djangoproject.com/en/4.1/ref/models/expressions/#exists-subqueries

Feature.objects.annotate(enabled=Exists(
    FeatureUserM2M.objects.filter(
        feature=OuterRef('pk'),
        user=request.user,
    )
))
Вернуться на верх