簡體   English   中英

django-rest-framework 覆蓋 get_queryset 並沿查詢集將附加數據傳遞給序列化程序

[英]django-rest-framework override get_queryset and pass additional data to serializer along queryset

這是我面臨的問題的一個玩具示例。 出於某種原因,我無法將預期的數據傳遞給我的序列化程序,這引發了以下錯誤。

/my-end-point/ 處的 AttributeError

嘗試獲取序列化ParentSerializer main_data上的字段main_data的值時出現ParentSerializer 序列化器字段可能命名不正確,並且與str實例上的任何屬性或鍵都不匹配。 原始異常文本是:“str”對象沒有屬性“main_data”。

class MainModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = MainModel


class ParentSerializer(serializers.Serializer):
    
    main_data = MainModelSerializer(many=True)
    extra_data = serializers.FloatField()
    

class View(ListCreateAPIView):
    
    serializer = ParentSerializer
    
    def get_queryset(self):
        # extra_data would have some calculated value which would be a float
        extra_data = some_calculated_value()
        queryset = MainModel.objects.filter(some filters)
        
        return {
            'main_data': queryset,
            'extra_data': extra_data
        }
        
        
# expected data that is passed to the ParentSerializer

# {
#     'main_data': queryset,
#     'extra_data': extra_data
# }

看起來你有兩個問題:

  1. get_queryset方法的返回值不正確
  2. 將一些額外的數據傳遞給序列化程序

至於第一個,您根本不應該覆蓋該方法或返回查詢集。 根據計算額外數據的方式,可以進行權衡,例如在查詢集上注釋值並在序列化器字段列表中指定它。

對於第二個 - 如果注釋不是一個選項並且您想計算一個值,可能的解決方案是將額外的數據添加到序列化器上下文並將其用作序列化器方法 field 的返回值。 在這種情況下,額外的數據將與模型記錄數據放在同一級別(每個模型記錄的額外字段):

{
    'model_field_1': 'value',
    ...
    'extra_field': 'value',
}

或者,您可以通過覆蓋list (並create ,如果需要)繼續使用嵌套關系的方法 - 只需將額外數據添加到序列化程序驗證的數據中,結果將如下所示:

{
    'extra_data': 'value',
    'main_data': [
        {'id': 1, 'field1': 'value', ...}
        ...
    ]
}
class View(ListCreateAPIView):
    
    serializer = ParentSerializer
    
    def list(self, request, *args, **kwargs):
        # extra_data would have some calculated value which would be a float
        extra_data = some_calculated_value()
        qs = self.get_queryset()
        data = self.get_serializer(qs, many=True).data
        data['extra_data'] = extra_data
        return Response({'data': data}, status=status.HTTP_200_OK, content_type = 'application/json' ) 

我認為您想要實現的是將一些額外的數據傳遞給ParentSerializer ,以便您的視圖上的list action返回。但是您的代碼中存在多個問題:

  1. get_queryset僅用於返回models.QuerySet的實例,用於確定允許視圖對哪些模型對象執行任何類型的操作。
  2. 這是對第一點的跟進, get_queryset不用於將數據傳遞給序列化程序,這是在Serializer程序初始化期間完成的。
  3. 您正在使用ModelSerializer但您沒有在Meta類上指定fields屬性,因為drf version 3.3不再允許,您必須定義fields屬性或exclude屬性。

至於實際上如何將額外數據傳遞給序列化程序,您可以通過多種方式做到這一點:

  1. 定義一個由Charnel在他的回答中提出的 SerializerMethodField , 這里的 drf 文檔描述,您的序列化程序將如下所示:
    class ParentSerializer(serializers.Serializer):
        main_data = MainDataSerializer(many=True)
        extra_data = serializers.SerializerMethodField(method_name="some_calculated_value")

        def some_calculated_value(self, obj):
            # calculate value here
            return value

請注意,此字段是只讀字段。

  1. 您可以在驗證期間將計算值注入最終結果,這將使您的序列化程序如下所示:
    class ParentSerializer(serializers.Serializer):
        main_data = MainDataSerializer(many=True)

        def validate(self, attrs):
            attrs["extra_data"] = some_calculated_value()
            return attrs
  1. 您還可以通過覆蓋視圖上的list函數並更改傳遞給序列化程序的數據來實現。

我個人更喜歡選項 1,因為SerializerMethodField符合目的,而validate函數應該僅用於驗證以遵守單一職責概念。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM