拥有这些模型(简化):
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))))
但是有两个问题:
- 我无法将用户传递给此经理(其硬编码用于测试)
- 当我想要此注释时,我无法为情景创建代理模型(见下文),它仅在我替换成分模型上的默认管理器时才有效。
此代码不起作用,因为使用了成分默认相关管理器:
class RecipeWithUserInfo(Recipe):
class Meta:
proxy = True
objects = UserRecipesManager()
ingredients = UserIngredientsManager()
它仅在我替换成分模型上的默认管理器时才有效(但这不是我想要的):
class Ingredient(models.Model):
...
objects = UserIngredientsManager()