Джанго аннотация на родственной модели

Имея эти модели (упрощенно):

class UserProfile(models.Model):  
    user = models.OneToOneField(User)
    products = models.ManyToManyField(Product, through='UserProduct')


class Product(models.Model):
    title = models.CharField(max_length=100, blank=False)


class UserProduct(models.Model):
    user = models.ForeignKey(UserProfile)
    product = models.ForeignKey(Product)


class Recipe(models.Model):
    ingredients = models.ManyToManyField(Product, through='Ingredient')


class Ingredient(models.Model):
    product = models.ForeignKey(Product)
    recipe = models.ForeignKey(Recipe)

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

>>> Recipe.objects.get_for_user(user=user)[0].ingredients[0].is_user_have
>>> True

Но, конечно, в других случаях я не хочу, чтобы это поле было связано с ингредиентами.

Я понимаю, что мне нужен пользовательский менеджер. Но простое решение - добавить "is_user_have" в качестве свойства к модели Ingredient, определить пользовательский менеджер с помощью метода get_for_user, вызвать базовый get_queryset, а затем заполнить это поле в цикле for- не работает.

ОБНОВЛЕНИЕ 1
Я понял, как получить аннотации, которые я хотел, вот мой пользовательский менеджер для ингредиентов:

class UserIngredientsManager(models.Manager):
    def get_queryset(self):
    result = super(UserIngredientsManager, self).get_queryset()

    return (result
        .annotate(
            user_have_count=models.Count(
                models.Case(
                    models.When(
                        # Hardcoded !!!
                        product__userproduct__user_id=1,
                        then=True),
                    output_field=models.IntegerField())))
        .annotate(
            is_user_have=models.Case(
                models.When(
                    user_have_count__gt=0,
                    then=models.Value(True)),
                output_field=models.BooleanField(),
                default=models.Value(False))))

Но есть две проблемы:

  1. Я не могу передать пользователя этому менеджеру (он жестко запрограммирован для тестирования)
  2. Я не могу создать прокси-модель для ситуаций, когда мне нужны эти аннотации (см. Ниже), она работает только тогда, когда я заменяю менеджер по умолчанию на модели Ingredient.

Этот код не работает, для ингредиентов по умолчанию используется связанный менеджер:

class RecipeWithUserInfo(Recipe):
    class Meta:
        proxy = True

    objects = UserRecipesManager()
    ingredients = UserIngredientsManager()

Это работает только тогда, когда я заменяю менеджер по умолчанию на модели Ingredient (но это не то, что я хочу):

class Ingredient(models.Model):
    ...
    objects = UserIngredientsManager()

0 ответов

Другие вопросы по тегам