3 votes

Minimiser les accès à la base de données dans Django : .values_list() dépend de la clause .filter() précédente

Je rencontre un problème avec une requête DB dans Django.

Ma base de données (models.py) :

class Food(models.Model):
    name = models.CharField(max_length=200)
    ...

class Combination(models.Model):
    food1 = models.ForeignKey(Food, related_name='food1')
    food2 = models.ForeignKey(Food, related_name='food2')
    ...

L'ordre de combinaison des aliments n'a pas d'importance pour mon problème.
En outre, chaque combinaison peut exister plusieurs fois (et dans les deux sens).

Par exemple, food1="chocolat" & food2="fruit" est la même chose que food2="chocolat" & food1="fruit".
et les deux combinaisons existent plusieurs fois.

Si je veux trouver toutes les combinaisons comprenant un aliment spécifique (identifié par food_id)
J'ai actuellement recours aux questions suivantes :

combinations1 = Combination.objects.filter(food1=food_id).values_list('food2')
combinations2 = Combination.objects.filter(food2=food_id).values_list('food1')

Cela fonctionne, mais nécessite un traitement ultérieur. J'ai essayé d'utiliser des objets Q avec OR, mais je n'ai pas réussi car la colonne extraite dépend du filtre...

Je sais que cette solution est loin d'être élégante. Devrais-je plutôt utiliser un champ personnalisé ou un champ CommaSeparatedIntegerField au lieu de deux champs alimentaires distincts dans Combination ? Existe-t-il un moyen d'obtenir toutes les valeurs demandées (des deux colonnes) en une seule frappe dans la base de données ?

Merci de m'avoir aidé !

Santé,
Oliver

2voto

dvd Points 477

Je pense que la meilleure solution est l'utilisation de l'objet Q, quelque chose comme

qs = Combination.objects.filter(Q(food1=food_id)|Q(food2=food_id).values_list('food1', 'food2')
combinations = set()
for row in qs:
   if row[0] == food_id:
       combinations.append(row[1])
   else:
       combinations.append(row[0])

2voto

Chris Wesseling Points 2881

N'est-ce pas

itertools.chain(Food(id=food_id).food1.all(), Food(id=food_id).food2.all())

ce que vous recherchez ?

Et si l'ordre des aliments dans les combinaisons n'a pas d'importance, pourquoi ne pas utiliser un ManyToManyField(Food) sur Combination ? Ensuite Food(id=food_id).combination_set.all() seront toutes les combinaisons qui contiennent cet aliment particulier.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X