2012-07-17 13 views
6

Estoy intentando utilizar Tastypie con relaciones ManyToMany utilizando modelos intermedios (a través de palabras clave) (https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships)Django tastypie: Obtener valores adicionales de un relaciones M2M utilizando modelo intermedio

estoy el trabajo con estos modelos:

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

he sido capaz de buscar la relación de muchos a muchos, pero no los campos extra . Aquí está mi código 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'] 

He estado tratando de utilizar un método de la variable sala de hidrato en mi PointResource así:

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 

Pero el problema es que crea tantas consultas como puntos tengo: es un asesino de rendimiento real cuando tienes +8000 Puntos.

No he podido encontrar ningún recurso útil para obtener rendimiento. Estaba pensando en hacer una consulta personalizada utilizando el método .extra() disponible para QuerySet, pero la palabra clave JOIN no está disponible (el parche ha sido rechazado hace un par de meses). Y no estoy seguro de que las subconsultas SELECT hagan el truco.

Respuesta

7

¿Ha considerado cambiar su consulta para utilizar el recurso PointPosition? A partir de los sonidos de la misma lo que "puntuales" se entiende en su base de datos no es en realidad lo mismo que "Punto" significa en su API por lo que es necesario que haya alguna traducción para ocultar los detalles internos:

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

Al Si no necesita ajustar sus parámetros de filtrado, esto evitará la necesidad de hacer más de una consulta. Su método dehydrate puede intercambiar los datos según sea necesario. También puede ahorrar algo de sobrecarga usando .values() para extraer solo los campos necesarios como diccionario en lugar de objetos completos.

+0

Muchas gracias por su respuesta. Eso es lo que hice, pero no pensé usar 'deshidratar' para intercambiar elementos para reordenar mi dictionario. Consejo genial :) – Solvik

+1

Pasé demasiado tiempo luchando contra tastypie antes de recordarme a mí mismo que se trata simplemente de construir una estructura de datos simple y que no había una sola forma correcta de construir un diccionario. Tengo al menos un recurso en el que un ModelResource reemplazado por gnarly se convirtió en un Recurso simple que simplemente llama al ORM directamente para construir eficientemente una estructura de datos intrincada. –

Cuestiones relacionadas