在Django REST框架中查询DB的最佳方法是什么

uklbhaso  于 2023-05-19  发布在  Go
关注(0)|答案(2)|浏览(148)

我有models.py

class Category(MPTTModel):
    # few fields

class Brand(models.Model):
    # few fields

class Attribute(models.Model):
   # few fields

class AttributeValue(models.Model):
   attributes = models.ForeignKey(Attribute, # other conditions)
   # few fields

class Product(models.Model):
   category = models.ForeignKey(Category, # other conditions)
   brand = models.ForeignKey(Brand, # other conditions)
   attributes = models.ManyToManyField(Attribute, # other conditions)
   # few other fields

class ProductImages(models.Model):
   product = models.ForeignKey(Product, # other conditions)

views.py中,我有

class ProductAPIView(generics.GenericAPIView):

    serializer_class = ProductSerializer
    queryset = Product.objects.all()

serializers.py

class ProductSerializer(serializers.ModelSerializer):
    brand = serializers.SlugRelatedField(queryset = Brand.objects.all())
    category = serializers.SlugRelatedField(queryset = Category.objects.all())
    attributes = AttributeSerializer(many = True, read_only = True)
    product_images = ProductImageSerializer(many = True, read_only = True)

我得到的JSON响应是这样的

{
    "brand": ...,
    "category": ...,
    "attributes": [
        { "attribute_values": [...] },
        { "attribute_values": [...] }
    ],
    "product_images": [{...}, {...}]
}

我遇到了select_relatedprefetch_related,它们将优化外键字段和多对多字段的数据库查询。
我将查询集更改为queryset = Product.objects.select_related('category', 'brand').all()
如何更改ProductAPIView中的查询集,使其同时包含attributesproduct_imagesattribute_values字段,并提高性能?

u91tlkcl

u91tlkcl1#

您可以链接select_realtedprefetch_related

class ProductAPIView(generics.GenericAPIView):

    serializer_class = ProductSerializer
    queryset = Product.objects.select_related('category', 'brand').prefetch_related("attributes")

或覆盖get_queryset函数

class ProductAPIView(generics.GenericAPIView):

    serializer_class = ProductSerializer
    
    def get_queryset(self):
        qs =  super().get_queryset()
        return qs.select_related('category', 'brand').prefetch_related("attributes")

你可以使用Prefetch类来指定在prefetch_related()中使用的查询集,并以这种方式将其与select_related()组合:

hlswsv35

hlswsv352#

对于你的问题的第一部分,你可以看看预取和这个问题。
为了调试的目的,我总是使用这个装饰器:

from django.db import connection, reset_queries
import time
import functools

def query_debugger(func):

    @functools.wraps(func)
    def inner_func(*args, **kwargs):

        reset_queries()
        
        start_queries = len(connection.queries)

        start = time.perf_counter()
        result = func(*args, **kwargs)
        end = time.perf_counter()

        end_queries = len(connection.queries)

        print(f"Function : {func.__name__}")
        print(connection.queries)
        print(f"Number of Queries : {end_queries - start_queries}")
        print(f"Finished in : {(end - start):.2f}s")
        return result

    return inner_func

然后像这样使用它:

@query_debugger
def get(self, request, *args, **kwargs):
   pass

相关问题