Je travaille à la création d'une application de recettes de cocktails comme exercice d'apprentissage.
J'essaie de créer un filtre via le cadre Rest de Django qui accepte une chaîne d'identifiants d'ingrédients via un paramètre de requête (?=ingredients_exclusive=1,3,4), puis recherche toutes les recettes qui contiennent tous ces ingrédients. Je voudrais rechercher "Tous les cocktails qui ont à la fois du rhum et de la grenadine" et ensuite aussi, séparément "Tous les cocktails qui ont du rhum, et tous les cocktails qui ont de la grenadine".
Les trois modèles de mon application sont Recipes, RecipeIngredients et IngredientTypes. Les recettes (Old Fashioned) ont plusieurs RecipeIngredients (2oz de Whiskey), et les RecipeIngredients sont tous d'un IngredientTypes (Whiskey). Je vais éventuellement changer le RecipeIngredient en un modèle de passage en fonction de ce que je décide de faire.
La liste peut être d'une longueur variable, je ne peux donc pas simplement enchaîner les fonctions de filtrage. Je dois parcourir la liste des identifiants en boucle, puis construire un Q().
Cependant, j'ai quelques problèmes. Par le biais du shell Django, j'ai fait ceci :
>>> x = Recipe.objects.all()
>>> q = Q(ingredients__ingredient_type=3) & Q(ingredients__ingredient_type=7)
>>> x.filter(q)
<QuerySet []>
>>> x.filter(ingredients__ingredient_type=3).filter(ingredients__ingredient_type=7)
<QuerySet [<Recipe: Rum and Tonic>]>
Voici donc ma question : Pourquoi l'objet Q qui AND les deux requêtes est-il différent des filtres enchaînés du même objet ?
J'ai lu l'article " Recherches complexes avec des objets Q "dans la documentation de Django et cela ne semble pas aider.
Juste pour référence, voici mes filtres dans Filters.py.
La version "OR" de cette commande fonctionne correctement :
class RecipeFilterSet(FilterSet):
ingredients_inclusive = django_filters.CharFilter(method='filter_by_ingredients_inclusive')
ingredients_exclusive = django_filters.CharFilter(method='filter_by_ingredients_exclusive')
def filter_by_ingredients_inclusive(self, queryset, name, value):
ingredients = value.split(',')
q_object = Q()
for ingredient in ingredients:
q_object |= Q(ingredients__ingredient_type=ingredient)
return queryset.filter(q_object).distinct()
def filter_by_ingredients_exclusive(self, queryset, name, value):
ingredients = value.split(',')
q_object = Q()
for ingredient in ingredients:
q_object &= Q(ingredients__ingredient_type=ingredient)
return queryset.filter(q_object).distinct()
class Meta:
model = Recipe
fields = ()
J'ai également inclus mes modèles ci-dessous :
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
class IngredientType(models.Model):
name = models.CharField(max_length=256)
CATEGORY_CHOICES = (
('LIQUOR', 'Liquor'),
('SYRUP', 'Syrup'),
('MIXER', 'Mixer'),
)
category = models.CharField(
max_length=128, choices=CATEGORY_CHOICES, default='MIXER')
def __str__(self):
return self.name
class Recipe(models.Model):
name = models.CharField(max_length=256)
def __str__(self):
return self.name
class RecipeIngredient(models.Model):
ingredient_type = models.ForeignKey(IngredientType, on_delete=models.CASCADE, related_name="ingredients")
quantity = models.IntegerField(default=0)
quantity_type = models.CharField(max_length=256)
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE, related_name="ingredients")
@property
def ingredient_type_name(self):
return self.ingredient_type.name
@property
def ingredient_type_category(self):
return self.ingredient_type.category
def __str__(self):
return f'{self.quantity}{self.quantity_type} of {self.ingredient_type}'
Toute aide serait très appréciée !