Django Queryset - 重命名原始值并重新使用原始值名称
Django Queryset - rename original values and re-use original value names
我正在完成一项工作挑战,我对这个端点的响应有点困惑。
我有以下型号:
Attribute
AttributeValue
ProductAttribute
我需要获取链接到给定产品 ID 的所有属性。我已经设法获得了这些值,但我无法在响应中为它们提供正确的名称。相关代码在get_attributes_from_product
函数中:
# src/api/viewsets/attribute.py
from django.db.models import F
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from api import errors
from api.models import Attribute, AttributeValue, ProductAttribute
from api.serializers import AttributeSerializer, AttributeValueSerializer, AttributeValueExtendedSerializer
import logging
logger = logging.getLogger(__name__)
class AttributeViewSet(viewsets.ReadOnlyModelViewSet):
"""
list: Return a list of attributes
retrieve: Return a attribute by ID.
"""
queryset = Attribute.objects.all()
serializer_class = AttributeSerializer
@action(detail=False, url_path='values/<int:attribute_id>')
def get_values_from_attribute(self, request, *args, **kwargs):
"""
Get Values Attribute from Attribute ID
"""
attribute_id = int(kwargs['attribute_id'])
# Filter queryset to find all values for attribute
response = AttributeValue.objects.filter(attribute_id=attribute_id).values(
'attribute_value_id', 'value')
# Return response
if response.exists():
return Response(response, 200)
else:
return Response(response, 204)
@action(detail=False, url_path='inProduct/<int:product_id>')
def get_attributes_from_product(self, request, *args, **kwargs):
"""
Get all Attributes with Product ID
"""
product_id = int(kwargs['product_id'])
# Filter all attributes in product
response = ProductAttribute.objects.filter(product_id=product_id).annotate(
original_attribute_value_id=F('attribute_value_id'),
original_attribute_value=F('attribute_value__value')).values(
attribute_name=F('attribute_value__attribute_id__name'),
attribute_value_id=F('attribute_value_id'),
attribute_value=F('attribute_value__value')
)
# Return response
if response.exists():
return Response(response, 200)
else:
return Response(response, 204)
如果我将 attribute_value_id=F('attribute_value_id')
和 attribute_value=F('attribute_value__value')
更改为 attribute_value_id1=F('attribute_value_id')
和 attribute_value1=F('attribute_value__value')
响应成功并且所有值都是正确的,但显然键名是错误的。
它应该 return 以下键:attribute_name
、attribute_value_id
和 attribute_value
。
django ORM 不会用注释字段的名称覆盖现有模型属性。
为了使用与现有模型属性冲突的名称,您需要使用
序列化程序 class 或在返回响应之前格式化查询集行。
可以在 django rest-framework 中找到使用序列化程序的示例
文档。
在不使用查询集的情况下,您可以在响应中使用 list
个 dict
个对象。这个
虽然是一个捷径,使用序列化程序可能会更好。
class AttributeViewSet(viewsets.ReadOnlyModelViewSet):
# ...
def render_product_attribute_row(self, row):
row["attribute_value_id"] = row.pop("tmp_attribute_value_id")
row["attribute_value"] = row.pop("tmp_attribute_value")
return row
@action(detail=False, url_path='inProduct/<int:product_id>')
def get_attributes_from_product(self, request, *args, **kwargs):
product_id = int(kwargs['product_id'])
queryset = ProductAttribute.objects.filter(product_id=product_id)
queryset = queryset.annotate(
original_attribute_value_id=F('attribute_value_id'),
original_attribute_value=F('attribute_value__value'),
)
queryset = queryset.values(
attribute_name=F('attribute_value__attribute_id__name'),
tmp_attribute_value_id=F('attribute_value_id'),
tmp_attribute_value=F('attribute_value__value'),
)
if queryset.exists():
status_code = 200
else:
status_code = 204
response = [self.render_product_attribute_row(row) for row in queryset]
return Response(response, status_code)
我正在完成一项工作挑战,我对这个端点的响应有点困惑。
我有以下型号:
Attribute
AttributeValue
ProductAttribute
我需要获取链接到给定产品 ID 的所有属性。我已经设法获得了这些值,但我无法在响应中为它们提供正确的名称。相关代码在get_attributes_from_product
函数中:
# src/api/viewsets/attribute.py
from django.db.models import F
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from api import errors
from api.models import Attribute, AttributeValue, ProductAttribute
from api.serializers import AttributeSerializer, AttributeValueSerializer, AttributeValueExtendedSerializer
import logging
logger = logging.getLogger(__name__)
class AttributeViewSet(viewsets.ReadOnlyModelViewSet):
"""
list: Return a list of attributes
retrieve: Return a attribute by ID.
"""
queryset = Attribute.objects.all()
serializer_class = AttributeSerializer
@action(detail=False, url_path='values/<int:attribute_id>')
def get_values_from_attribute(self, request, *args, **kwargs):
"""
Get Values Attribute from Attribute ID
"""
attribute_id = int(kwargs['attribute_id'])
# Filter queryset to find all values for attribute
response = AttributeValue.objects.filter(attribute_id=attribute_id).values(
'attribute_value_id', 'value')
# Return response
if response.exists():
return Response(response, 200)
else:
return Response(response, 204)
@action(detail=False, url_path='inProduct/<int:product_id>')
def get_attributes_from_product(self, request, *args, **kwargs):
"""
Get all Attributes with Product ID
"""
product_id = int(kwargs['product_id'])
# Filter all attributes in product
response = ProductAttribute.objects.filter(product_id=product_id).annotate(
original_attribute_value_id=F('attribute_value_id'),
original_attribute_value=F('attribute_value__value')).values(
attribute_name=F('attribute_value__attribute_id__name'),
attribute_value_id=F('attribute_value_id'),
attribute_value=F('attribute_value__value')
)
# Return response
if response.exists():
return Response(response, 200)
else:
return Response(response, 204)
如果我将 attribute_value_id=F('attribute_value_id')
和 attribute_value=F('attribute_value__value')
更改为 attribute_value_id1=F('attribute_value_id')
和 attribute_value1=F('attribute_value__value')
响应成功并且所有值都是正确的,但显然键名是错误的。
它应该 return 以下键:attribute_name
、attribute_value_id
和 attribute_value
。
django ORM 不会用注释字段的名称覆盖现有模型属性。
为了使用与现有模型属性冲突的名称,您需要使用 序列化程序 class 或在返回响应之前格式化查询集行。
可以在 django rest-framework 中找到使用序列化程序的示例 文档。
在不使用查询集的情况下,您可以在响应中使用 list
个 dict
个对象。这个
虽然是一个捷径,使用序列化程序可能会更好。
class AttributeViewSet(viewsets.ReadOnlyModelViewSet):
# ...
def render_product_attribute_row(self, row):
row["attribute_value_id"] = row.pop("tmp_attribute_value_id")
row["attribute_value"] = row.pop("tmp_attribute_value")
return row
@action(detail=False, url_path='inProduct/<int:product_id>')
def get_attributes_from_product(self, request, *args, **kwargs):
product_id = int(kwargs['product_id'])
queryset = ProductAttribute.objects.filter(product_id=product_id)
queryset = queryset.annotate(
original_attribute_value_id=F('attribute_value_id'),
original_attribute_value=F('attribute_value__value'),
)
queryset = queryset.values(
attribute_name=F('attribute_value__attribute_id__name'),
tmp_attribute_value_id=F('attribute_value_id'),
tmp_attribute_value=F('attribute_value__value'),
)
if queryset.exists():
status_code = 200
else:
status_code = 204
response = [self.render_product_attribute_row(row) for row in queryset]
return Response(response, status_code)