Having these models (simplified):
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)
I need in some cases to get a list of recipes, marked on each ingredient, "whether it is user have that product.". And, maybe other calculated fields, according to given user. Example of what i want:
>>> Recipe.objects.get_for_user(user=user)[0].ingredients[0].is_user_have
>>> True
But, of course, in other cases i don't want that field attached to ingredients.
I understand that the i need custom manager. But straightforward solution - add "is_user_have" as property to Ingredient model, define custom manager with get_for_user method, call base get_queryset and then in for-loop populate that field - doesn't work.
UPDATE 1
I figured out how to get annotations that i wanted, here is my custom manager for ingredients:
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))))
But there are two problems:
- I can't pass user to this manager (its hardcoded for testing)
- I can't create proxy model for situtations when i want this annotations (see below), it only works when i replace default manager on Ingredient model.
This code doesn't work, for ingredients default related manager used instead:
class RecipeWithUserInfo(Recipe):
class Meta:
proxy = True
objects = UserRecipesManager()
ingredients = UserIngredientsManager()
It works only when i replace default manager on Ingredient model (but that not what i want):
class Ingredient(models.Model):
...
objects = UserIngredientsManager()