2016-01-17 5 views
9

In resources.py ich habe:Wie zu beschleunigen tastypie die Abfragen mit ToManyField

class CategoryResource(ModelResource): 
    items = fields.ToManyField('ItemResource', 'items', full=True, null=False, readonly=True, related_name='items') 
    class Meta: 
     queryset = Category.objects.all().order_by('id') 
     include_resource_uri = False 
     always_return_data = True 
     resource_name = 'category' 

Es gibt etwa 5000 Artikel in 6 Kategorien. Wenn ich eine "liste" api-Anfrage mache, d. H. "Api/1.0/Kategorie", macht es etwa 5000 Abfragen an die Datenbank. Wie kann ich es optimieren? Ich weiß über voll = Falsch, aber es ist nicht meine Bedürfnisse.

UPD: Ich fand, was so viele Anfragen verursacht. Ich habe eine "Kategorien" -Beziehung in ItemResource, also erzeugt tastypie eine Select-Abfrage für jedes Element.

Offensichtlich sind das unnötige Daten, wenn ich eine CategoryResource anfordere, gibt es eine Möglichkeit, sie von Abfragen auszuschließen?

Antwort

3

Versuchen Sie folgendes:

def get_object_list(self, request): 
    return super(CategoryResource, self).get_object_list(request) \ 
     .prefetch_related('items', 'items__categories') 

Verwenden Sie keine select_related, weil es doppelte Zeilen zurück.

prefetch_related eine Abfrage erstellt, die alle Elemente zurückgibt, und Django ORM stimmt sie mit den richtigen Zeilen ab.

EDIT

ändern dehydrate_categories

def dehydrate_categories(self, bundle): 
    return [category.name for category in bundle.obj.categories.all() if category.owner == bundle.request.user] 
+0

Nicht für mich arbeiten - alles bleibt gleich – svfat

+1

Show 'ItemResource' und Modelle –

+0

EDIT: SO vermasselte meine Formatierung, so dass ich als eine andere Antwort posten. | Wenn es immer noch ein Problem gibt, könnte ItemResource auch ein oder mehrere verwandte Felder haben. Wenn das der Fall ist, können Sie wahrscheinlich so etwas wie: def get_object_list (self, Anfrage): return Super (CategoryResource, Selbst-) .get_object_list (Anfrage) .prefetch_related ('items__relatedfield1', 'items__relatedfield2') Haltungsart Denken Sie daran, dass Änderungen an Querysets wie "select_related" oder "prefetch_related", die für "ItemResource" ausgeführt werden, die Abfrage für verwandte Modelle in 'CategoryResource' nicht beeinflussen. –

2

Wenn es immer noch ein Problem, könnte es sein, dass ItemResource hat auch ein oder mehr Felder zusammen. Wenn das der Fall ist, können Sie wahrscheinlich so etwas wie:

def get_object_list(self, request): 
    return super(CategoryResource, self).get_object_list(request).prefetch_related('items__relatedfield1', 'items__relatedfield2') 

Beachten Sie, alle queryset Veränderungen wie select_related oder prefetch_related auf ItemResource durchgeführt wird die Abfrage nicht für verwandte Modelle auf CategoryResource beeinflussen.

UPDATE: Probieren Sie etwas wie folgt aus:

class CategoryResource(ModelResource): 
    items = fields.ToManyField('ItemResource', 'items', full=True, null=False, readonly=True, related_name='items') 

    class Meta: 
     queryset = Category.objects.all().order_by('id') 
     include_resource_uri = False 
     always_return_data = True 
     resource_name = 'category' 

    def get_object_list(self, request): 
     return super(CategoryResource, self).get_object_list(request) \ 
      .prefetch_related('items', 'items__categories') 

class ItemResource(ModelResource): 
    categories = fields.ToManyField(CategoryResource, 'categories', null=True, readonly=True) 

    def dehydrate_categories(self, bundle): 
     categories = items__item=bundle.obj.categories.all() 
     return [ 
      category.name 
      for category in categories 
      if category.owner_id == bundle.request.user.id 
     ] 

OR:

class CategoryResource(ModelResource): 
    items = fields.ToManyField('ItemResource', 'items', full=True, null=False, readonly=True, related_name='items') 

    class Meta: 
     queryset = Category.objects.all().order_by('id') 
     include_resource_uri = False 
     always_return_data = True 
     resource_name = 'category' 

    def get_object_list(self, request): 
     return super(CategoryResource, self).get_object_list(request) \ 
      .prefetch_related(
       'items', 
       Prefetch('items__categories', queryset=Category.objects.filter(owner_id=bundle.request.user.id)) 
      ) 

class ItemResource(ModelResource): 
    categories = fields.ToManyField(CategoryResource, 'categories', null=True, readonly=True) 

    def get_object_list(self, request): 
     return super(ItemResource, self).get_object_list(request) \ 
      .prefetch_related(
       Prefetch('categories', queryset=Category.objects.filter(owner_id=bundle.request.user.id)) 
      ) 

    def dehydrate_categories(self, bundle): 
     return [ 
      category.name 
      for category in bundle.obj.categories.all() 
     ] 

Außerdem können Sie wahrscheinlich eine Listfield für ItemResource.categories statt ToManyField verwenden, da Sie manuell sind Handhabung der Dehydrierung.

+0

Bitte schauen Sie auf UPD – svfat

+0

ich habe" Item-Objekt hat kein Attribut 'Kategorien' "Fehler – svfat

+1

Versuchen Sie Category_set statt. Ich habe "item.categories" aus dem von Ihnen bereitgestellten Code erhalten. –

Verwandte Themen