1

拥有这些模型(简化):

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”作为属性添加到成分模型,使用 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. 当我想要此注释时,我无法为情景创建代理模型(见下文),它仅在我替换成分模型上的默认管理器时才有效。

此代码不起作用,因为使用了成分默认相关管理器:

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

    objects = UserRecipesManager()
    ingredients = UserIngredientsManager()

它仅在我替换成分模型上的默认管理器时才有效(但这不是我想要的):

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

0 回答 0