2016-01-17 15 views
9

Trong resources.py tôi có:Làm thế nào để tăng tốc độ truy vấn tastypie với 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' 

Có khoảng 5000 mục trong 6 hạng mục. Khi tôi đưa ra yêu cầu api 'list' tức là 'api/1.0/category', nó tạo ra khoảng 5000 truy vấn tới cơ sở dữ liệu. Làm thế nào tôi có thể tối ưu hóa nó? Tôi biết về đầy đủ = Sai, nhưng nó không phù hợp với nhu cầu của tôi.

UPD: Tôi đã tìm thấy nguyên nhân gây ra quá nhiều truy vấn. Tôi có mối quan hệ 'loại' trong ItemResource, do đó, việc tạo ra một truy vấn chọn cho từng mục.

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

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

Rõ ràng đó là dữ liệu không cần thiết khi tôi yêu cầu CategoryResource, có cách nào để loại trừ khỏi truy vấn không?

Trả lời

3

Hãy thử điều này:

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

Không sử dụng select_related, bởi vì nó trả lại hàng trùng lặp.

prefetch_related thực hiện một truy vấn, trả về tất cả các mục và Django ORM khớp với các mục phù hợp.

EDIT

Thay đổi dehydrate_categories

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

Không hoạt động cho tôi - tất cả vẫn giữ nguyên – svfat

+1

Hiển thị 'ItemResource' và kiểu –

+0

CHỈNH SỬA: SO đã làm hỏng định dạng của tôi, vì vậy tôi đã đăng lại làm câu trả lời khác. | Nếu vẫn còn một vấn đề, có thể là ItemResource cũng có một hoặc nhiều trường liên quan. Nếu đó là trường hợp, bạn có lẽ có thể làm điều gì đó như: def get_object_list (tự, theo yêu cầu): trở lại siêu (CategoryResource, tự) .get_object_list (theo yêu cầu) .prefetch_related ('items__relatedfield1', 'items__relatedfield2') Hãy tâm trí, bất kỳ sự thay đổi queryset nào như 'select_related' hoặc' prefetch_related được thực hiện trên 'ItemResource' sẽ không ảnh hưởng đến truy vấn cho các mô hình liên quan trên' CategoryResource'. –

2

Nếu vẫn còn một vấn đề, nó có thể là ItemResource cũng có một hoặc nhiều lĩnh vực liên quan. Nếu đó là trường hợp, bạn có lẽ có thể làm điều gì đó như:

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

Hãy ghi nhớ, bất kỳ thay đổi queryset như select_related hoặc prefetch_related thực hiện trên ItemResource sẽ không ảnh hưởng đến truy vấn cho các mô hình liên quan về CategoryResource.

UPDATE: Hãy thử một cái gì đó như thế này:

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() 
     ] 

Ngoài ra, bạn có thể có thể sử dụng một ListField thay vì ToManyField cho ItemResource.categories vì ​​bạn đang tự xử lý mất nước.

+0

hãy nhìn vào UPD – svfat

+0

Tôi đã có" Mục đối tượng không có thuộc tính 'danh mục' "lỗi – svfat

+1

Hãy thử category_set thay thế. Tôi có "item.categories" từ mã bạn đã cung cấp. –

Các vấn đề liên quan