2012-07-17 9 views
6

Sto cercando di utilizzare Tastypie con relazioni ManyToMany utilizzando modelli intermedi (attraverso parola chiave) (https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships)django tastypie: Ottenere extra-valori di un rapporto M2M usando il modello intermedio

Sono Lavorare con questi modelli:

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')) 

sono stato in grado di recuperare la relazione molti-a-molti, ma non i campi aggiuntivi . Ecco il mio codice tastypie:

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'] 

Ho cercato di utilizzare un metodo per variabile stanza idrato nel mio PointResource come questo:

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 

Ma il problema è che crea tante domande quante ne ho: è un vero e proprio killer con prestazioni pari a quando si hanno +8000 punti.

Non sono stato in grado di trovare risorse utili per ottenere prestazioni. Stavo pensando di fare una query personalizzata usando il metodo .extra() disponibile per QuerySet, ma la parola chiave JOIN non è disponibile (la patch è stata rifiutata un paio di mesi fa). E non sono sicuro che SELECT subquery farebbe il trucco.

risposta

7

Hai considerato di cambiare il tuo queryset per utilizzare la risorsa PointPosition? Dai suoni di esso ciò che "Point" significa nel database, non è in realtà la stessa cosa "Punto" significa nella vostra API quindi ci deve essere qualche traduzione per nascondere i dettagli interni:

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

Alla spese di dover regolare i parametri di filtraggio, questo eviterà la necessità di fare più di una query. Il tuo metodo dehydrate può scambiare i dati in base alle esigenze. Potresti anche risparmiare un po 'di overhead usando .values() per estrarre solo i campi necessari come un dizionario piuttosto che oggetti completi.

+0

Grazie mille per la risposta. Questo è in effetti quello che ho fatto, ma non ho pensato di usare 'disidratato' per scambiare elementi per riordinare il mio dizionario. Suggerimento cool :) – Solvik

+1

Ho passato troppo tempo a combattere il tasteypie prima di ricordare a me stessa che si trattava solo di costruire una semplice struttura dati e che non c'era un solo modo giusto per costruire un dizionario. Ho almeno una risorsa in cui ModelResource gnarly sovrascritto è diventato una risorsa semplice che chiama semplicemente l'ORM direttamente per creare in modo efficiente una struttura di dati complessa. –