英文:
What is the best method to query db in django rest framework
问题
我有models.py
class Category(MPTTModel):
# 几个字段
class Brand(models.Model):
# 几个字段
class Attribute(models.Model):
# 几个字段
class AttributeValue(models.Model):
attributes = models.ForeignKey(Attribute, # 其他条件)
# 几个字段
class Product(models.Model):
category = models.ForeignKey(Category, # 其他条件)
brand = models.ForeignKey(Brand, # 其他条件)
attributes = models.ManyToManyField(Attribute, # 其他条件)
# 其他字段
class ProductImages(models.Model):
product = models.ForeignKey(Product, # 其他条件)
在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_related
和prefetch_related
可以优化外键字段和多对多字段的数据库查询。
我将查询集更改为queryset = Product.objects.select_related('category', 'brand').all()
如何在ProductAPIView
中更改查询集以包括attributes
、product_images
和attribute_values
字段,并提高性能?
英文:
I have 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)
In views.py
, I have
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)
I'm getting my json response like this
{
"brand": ...,
"category": ...,
"attributes": [
{ "attribute_values": [...] },
{ "attribute_values": [...] }
],
"product_images": [{...}, {...}]
}
I came across select_related
and prefetch_related
which will optimise the db queries on foreign key fields and many-to-many fields.
I changed the queryset to queryset = Product.objects.select_related('category', 'brand').all()
How can i change the queryset in ProductAPIView to include the attributes
, product_images
and attribute_values
fields also and improve the performance here ?
答案1
得分: 1
以下是您要翻译的部分:
"for the first part of your question you can take a look at Prefetch and this question.
for debugging purposes I always use this decorator:
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
And use it like this:
@query_debugger
def get(self, request, *args, **kwargs):
pass
```"
<details>
<summary>英文:</summary>
for the first part of your question you can take a look at [Prefetch](https://docs.djangoproject.com/en/4.2/ref/models/querysets/#django.db.models.Prefetch)
and this [question](https://stackoverflow.com/questions/54569384/django-chaining-prefetch-related-and-select-related?answertab=scoredesc#tab-top).
for debugging purposes I always use this decorator:
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
And use it like this:
@query_debugger
def get(self, request, *args, **kwargs):
pass
</details>
# 答案2
**得分**: 1
你可以链式使用 `select_related` 和 `prefetch_related`:
```python
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()
结合使用:
英文:
you can chain select_realted
& prefetch_related
class ProductAPIView(generics.GenericAPIView):
serializer_class = ProductSerializer
queryset = Product.objects.select_related('category', 'brand').prefetch_related("attributes")
or override get_queryset
function
class ProductAPIView(generics.GenericAPIView):
serializer_class = ProductSerializer
def get_queryset(self):
qs = super().get_queryset()
return qs.select_related('category', 'brand').prefetch_related("attributes")
You can use the Prefetch class to specify the queryset that is used in prefetch_related() and this way combine it with select_related():
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论