【问题标题】:Django Queryset - rename original values and re-use original value namesDjango Queryset - 重命名原始值并重新使用原始值名称
【发布时间】:2020-03-16 19:24:38
【问题描述】:

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

我有以下型号:

  • 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') 响应成功并且所有值都正确,但显然键名是错误的。

它应该返回以下键:attribute_nameattribute_value_idattribute_value

【问题讨论】:

    标签: django python-3.x django-models django-rest-framework django-queryset


    【解决方案1】:

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

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

    An example of using a serializer can be found in the django rest-framework documentation.

    不使用查询集,您可以在响应中使用 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)
    

    【讨论】:

    • 谢谢,达蒙!这真的帮助了我。现在阅读序列化程序类并尝试了解如何做到这一点,如果我没有及时得到它,我将坚持上面的解决方案。欣赏它。
    猜你喜欢
    • 1970-01-01
    • 2019-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-17
    • 2017-04-30
    • 1970-01-01
    • 2012-04-28
    相关资源
    最近更新 更多