Question

J'ai besoin d'aide mettre sur pied cette requête dans Django. J'ai simplifié l'exemple ici juste coupe droite au point.

MyModel(models.Model):
    created = models.DateTimeField()
    user = models.ForeignKey(User)
    data = models.BooleanField()

La requête que je voudrais créer en anglais sonnerait comme:

Donne-moi chaque enregistrement qui a été créé hier pour lesquels des données est faux où le fait que les données mêmes de gamme ne semble jamais aussi vrai pour l'utilisateur donné

Voici un exemple d'entrée / sortie en cas qui n'a pas été clair.

Valeurs Tableau

ID   Created    User    Data

1    1/1/2010   admin   False
2    1/1/2010   joe     True
3    1/1/2010   admin   False
4    1/1/2010   joe     False
5    1/2/2010   joe     False

Sortie queryset

1    1/1/2010   admin   False
3    1/1/2010   admin   False

Qu'est-ce que je cherche à faire est d'exclure enregistrement n ° 4. La raison en est que dans la plage donnée « hier », les données apparaît comme vrai une fois pour l'utilisateur dans le dossier n ° 2, donc qui exclurait notice # 4.

Dans un sens, il semble presque comme il y a 2 requêtes en cours. L'un pour déterminer les enregistrements dans la plage donnée, et un à exclure les dossiers qui se croisent avec les enregistrements « True ».

Comment puis-je faire cette requête avec le Django ORM?

Était-ce utile?

La solution

Vous n'avez pas besoin d'une requête imbriquée. Vous pouvez générer une liste des mauvais utilisateurs de PKs et d'exclure les enregistrements contenant les clés primaires dans la requête suivante.

bad = list(set(MyModel.obejcts.filter(data=True).values_list('user', flat=True)))
# list(set(list_object)) will remove duplicates
# not needed but might save the DB some work

rs = MyModel.objects.filter(datequery).exclude(user__pk__in=bad)
# might not need the pk in user__pk__in - try it

Vous pouvez condenser qui décompose en une ligne, mais je pense que ce aussi propre que vous obtiendrez. 2 requêtes ne sont pas si mal.

Edit: Vous pouvez wan lire la documentation à ce sujet:

http://docs.djangoproject.com/en/dev / ref / modèles / QuerySets / #

Il fait sonner comme il nids automatiques de la requête (donc seulement un des incendies de requête dans la base de données) si elle est comme ceci:

bad = MyModel.objects.filter(data=True).values('pk')
rs  = MyModel.objects.filter(datequery).exclude(user__pk__in=bad)

et MySQL n'optimise pas si bien que mon code ci-dessus (2 requêtes complètes) peut réellement finir par courir beaucoup plus vite.

Essayez les deux et faire la course!

Autres conseils

ressemble, vous pouvez utiliser: de django.db.models importer F MyModel.objects.filter(datequery).filter(data=False).filter(data = F('data'))

objet F disponible à partir de la version 1.0

S'il vous plaît, testez-le, je ne suis pas sûr.

Merci à l'évaluation paresseuse, vous pouvez casser votre requête en un petit nombre de variables différentes pour le rendre plus facile à lire. Voici un peu de temps de jeu de ./manage.py shell dans le style Oli déjà présenté.

> from django.db import connection
> connection.queries = []
> target_day_qs = MyModel.objects.filter(created='2010-1-1')
> bad_users = target_day_qs.filter(data=True).values('user')
> result = target_day_qs.exclude(user__in=bad_users)
> [r.id for r in result]
[1, 3]
> len(connection.queries)
1

On pourrait dire aussi result.select_related() si vous vouliez tirer dans les objets utilisateur dans la même requête.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top