2017-08-09 1 views
0

Je suis actuellement aux prises avec le comportement des sous-ensembles de django avec les annotations et les opérateurs inclus | et &Conserver les annotations du jeu de queues après la combinaison des ensembles de queues

J'ai modèles comme ceci:

class Property(models.Model): 
    value = models.IntegerField(null=True) 

    obj = PropertyManager() 

class Profile(models.Model): 
    name = models.CharField() 
    values = models.ManyToManyField(Property) 

class PropertyManager(models.Manager): 
    def included(self, profile): 
     super(PropertyManager, self).filter(Q(property__profile=profile)).annotate(included_value=Value('true', output_field=CharField())) 

    def excluded(self, profile): 
     super(PropertyManager, self).filter(~Q(property__profile=profile)).annotate(included_value=Value('false', output_field=CharField())) 

    def included_excluded(self, profile): 
     return (self.excluded(profile) | self.included(profile)).distinct() 

je naïvement attendu que la fonction included_excluded retourne un queryset rejoint des deux QuerySets avec leurs annotations, comme:

property_id | included_value 
------------|--------------- 
      1 | true 
      2 | false 

mais il se trouve , que l'annotation est écrasée dans mes exemples:

j = Profile.objects.get(id=1) 
exc = Property.obj.excluded(profile=j) 
inc = Property.obj.included(profile=j) 
all = Property.obj.included_excluded(profile=j) 

len(inc) => 14 
len(exc) => 17 
len(all) => 31 

all.values_list("included_value") => <QuerySet [('false',)]> 
exc.values_list("included_value") => <QuerySet [('false',)]> 
inc.values_list("included_value") => <QuerySet [('true',)]> 

all n'a évidemment pas toutes les valeurs correctes dans les annotations, comme je m'y attendais.

Je me demande, s'il y a une méthode pour joindre deux QuerySets et de garder les annotations faites plus tôt que je

Répondre

0

De Django 1.8 vers le haut, vous pouvez le faire comme ceci:

from django.db import models 
from django.db.models import Case, When 

def included_excluded(self, profile): 
    return super(PropertyManager, self).annotate(
     included_value=Case(
      When(property__profile=profile, then='true'), 
      default='false', output_field=models.CharField() 
     ) 
    ) 

Si vous besoin d'eux séparément, vous pouvez ensuite filtrer juste ce queryset: PropertyManager().included_excluded(profile).filter(included_value='true').