2012-07-17 13 views
6

Ich versuche Tastypie mit ManyToMany Beziehungen mit Zwischen Modellen (durch Stichwort) (https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships)django tastypie: Erster Extra-Wert einer m2m Beziehungen mit Zwischenmodell

Ich bin zu verwenden Arbeit mit diesen Modellen:

class Point(models.Model): 
    ... 
    value = models.FloatField(_('Value'), null=True) 
    rooms = models.ManyToManyField('rooms.Room', through='points.PointPosition') 

class Room(models.Model): 
    title = models.CharField(max_length=64) 

class PointPosition(models.Model): 
    point = models.ForeignKey('points.Point', verbose_name=_('Point')) 
    room = models.ForeignKey('rooms.Room', verbose_name=_('Room')) 
    x = models.IntegerField(_('Y')) 
    y = models.IntegerField(_('X')) 

ich habe in der Lage, die viele-zu-viele-Beziehung, aber nicht die zusätzlichen Felder zu holen . Hier ist mein tastypie Code:

class PointResource(ModelResource): 
    class Meta: 
     queryset = Point.objects.select_related(
      depth=10 
      ).prefetch_related('rooms').all() 
     resource_name = 'point' 
     allowed_methods = ['get'] 

    ... 
    value = fields.FloatField() 
    rooms = fields.ToManyField('rooms.api.RoomResource', 'rooms', full=True) 

class RoomResource(ModelResource): 
    class Meta: 
     queryset = Room.objects.all() 
     resource_name = 'room' 
     allowed_methods = ['get'] 

Ich habe versucht, eine Methode zu Hydrat Raum Variable zu verwenden in meinem PointResource wie folgt aus:

def dehydrate_rooms(self, bundle):                                                       
    rooms = []                                                            
    for room in bundle.obj.rooms.all():                                                      
     position = PointPosition.objects.get(                                                    
      room_id = room.pk,                                                        
      point_id = bundle.obj.pk)                                                            
     rooms.append({'id': room.pk,                                                         
      'title': room.title,                                                       
      'x': position.x,                                                        
      'y': position.y})                                                            
    return rooms 

Aber das Problem ist, dass es schafft so viele Fragen wie ich habe Punkte: es ist ein echter Performance-Killer, wenn Sie +8000 Punkte haben.

Ich konnte keine nützlichen Ressourcen finden, um Leistung zu erzielen. Ich dachte daran, eine benutzerdefinierte Abfrage mit der für QuerySet verfügbaren Methode .extra() durchzuführen, aber das Schlüsselwort JOIN ist nicht verfügbar (der Patch wurde vor ein paar Monaten abgelehnt). Und ich bin mir nicht sicher, SELECT Unterabfragen würden den Trick tun.

Antwort

7

Haben Sie darüber nachgedacht, das Abfrageset so zu ändern, dass die Ressource PointPosition verwendet wird? Von den Klängen der es was „Point“ in Ihrer Datenbank bedeutet, ist eigentlich nicht das gleiche wie das, was „Punkt“ bedeutet in der API so einige Übersetzung es muss sein, um die internen Details zu verbergen:

class PointResource(ModelResource): 
    class Meta: 
     queryset = PointPosition.objects.select_related("point", "room") 
     resource_name = 'point' 
     allowed_methods = ('get',) 

Bei der Wenn Sie Ihre Filterparameter anpassen müssen, müssen Sie nicht mehr als eine Abfrage ausführen. Ihre dehydrate Methode kann die Daten nach Bedarf austauschen. Sie können auch etwas Overhead sparen, indem Sie .values() verwenden, um nur die notwendigen Felder als ein Wörterbuch anstatt vollständige Objekte herauszuziehen.

+0

Vielen Dank für Ihre Antwort. Das ist in der Tat, was ich tat, aber ich dachte nicht, 'dehydrieren' zu verwenden, um Elemente zu tauschen, um mein Wörterbuch neu zu ordnen. Cooler Tipp :) – Solvik

+1

Ich verbrachte zu viel Zeit damit, tastypie zu bekämpfen, bevor ich mich daran erinnerte, dass es nur eine einfache Datenstruktur erstellt und es gab keinen einzigen richtigen Weg, ein Wörterbuch zu erstellen. Ich habe mindestens eine Ressource, bei der eine gnadenlos überschriebene ModelResource zu einer einfachen Ressource wurde, die das ORM direkt aufruft, um effizient eine komplizierte Datenstruktur aufzubauen. –