2009-09-13 7 views
1

Je veux obtenir tous les objets Geom qui sont liés à un certain content_object (voir la fonction que je suis en train de construire au fond, get_geoms_for_obj()queryset d'objets grâce à un modèle intermédiaire

class Geom(models.Model): 
    ... 

class GeomRelation(models.Model): 
    ''' For tagging many objects to a Geom object and vice-versa''' 

    geom = models.ForeignKey(Geom) 
    content_type = models.ForeignKey(ContentType) 
    object_id = models.PositiveIntegerField() 
    content_object = generic.GenericForeignKey() 

def get_geoms_for_object(obj): 
    ''' takes an object and gets the geoms that are related 

    ''' 
    ct = ContentType.objects.get_for_model(obj) 
    id = obj.id 
    grs = GeomRelation.objects.filter(content_type=ct, object_id=id) 
    # how with django orm magic can I build the queryset instead of list 
    # like below to get all of the Geom objects for a given content_object 
    geoms = [] 
    for gr in grs: 
     geoms.append(gr.geom) 
    return set(geoms) 
    # A set makes it so that I have no redundant entries but I want the 
    # queryset ordering too .. need to make it a queryset for so many reasons... 

Répondre

1

Duh,

return Geom.objects.filter(geomrelation__in=grs) 
+0

toujours si quelqu'un a quelque chose à ajouter ou des objections ou des commentaires, je vais laisser cela ouvert pour un peu. –

1

Si votre classe Geom possède une propriété generic.GenericRelation(), vous pouvez obtenir les objets par une norme par rapport à l'envers.

class Geom(models.Model): 
    ... 
    geom_relations = generic.GenericRelation(GeomRelation) 

Cette propriété est uniquement Python, qui ne nécessite pas de modification de la base de données. Maintenant, pour obtenir les geom_relations, vous venez de faire:

geom.geom_relations.all() 
0

Si vous passez un objet queryset comme argument de filtre pour une autre, l'ORM utilisera les instructions select imbriquées. Il est préférable de mettre en relation les relations de table dans les recherches de filtres; alors l'ORM utilisera une simple clause WHERE sur le JOIN, ce qu'il doit faire de toute façon. La différence de performance est significative:

In [2]: from django.db import connection 
In [3]: from app.models import * 
In [4]: ct = ContentType.objects.get_for_model(Thing) 
In [5]: grs = GeomRelation.objects.filter(content_type=ct, object_id=2) 
In [6]: 
In [7]: # slow method 
In [8]: list(Geom.objects.filter(geomrelation__in=grs)); 
In [9]: connection.queries[-1] 
Out[9]: 
{'sql': u'SELECT "app_geom"."id" FROM "app_geom" INNER JOIN "app_geomrelation" ON ("app_geom"."id" = "app_geomrelation"."geom_id") WHERE "app_geomrelation"."id" IN (SELECT U0."id" FROM "app_geomrelation" U0 WHERE (U0."content_type_id" = 10 AND U0."object_id" = 2))', 
'time': '0.140'} 
In [10]: 
In [11]: # fast method 
In [12]: list(Geom.objects.filter(geomrelation__content_type=ct, 
    ....:       geomrelation__object_id=2)); 
In [13]: connection.queries[-1] 
Out[13]: 
{'sql': u'SELECT "app_geom"."id" FROM "app_geom" INNER JOIN "app_geomrelation" ON ("app_geom"."id" = "app_geomrelation"."geom_id") WHERE ("app_geomrelation"."object_id" = 2 AND "app_geomrelation"."content_type_id" = 10)', 
'time': '0.001'}