Django Queryset - 重命名原始值并重新使用原始值名称

Django Queryset - rename original values and re-use original value names

我正在完成一项工作挑战,我对这个端点的响应有点困惑。

我有以下型号:

我需要获取链接到给定产品 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_nameattribute_value_idattribute_value

django ORM 不会用注释字段的名称覆盖现有模型属性。

为了使用与现有模型属性冲突的名称,您需要使用 序列化程序 class 或在返回响应之前格式化查询集行。

可以在 django rest-framework 中找到使用序列化程序的示例 文档。

在不使用查询集的情况下,您可以在响应中使用 listdict 个对象。这个 虽然是一个捷径,使用序列化程序可能会更好。

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)