DjangoRestFramework,如何向序列化器添加不来自模型的可选字段

huangapple go评论47阅读模式
英文:

DjangoRestFramework, how to add optional field not coming from model to serializer

问题

class CamperSerializer(serializers.ModelSerializer):

    camper_id = serializers.IntegerField(source='id')
    weather = serializers.SerializerMethodField('get_weather', read_only=True)

    def get_weather(self, instance):
        # Add your logic to fetch weather here
        lat = instance.location.y
        lon = instance.location.x
        return getWeatherFromLatLon(lat, lon)

    class Meta:
        model = Camper
        fields = ('camper_id', 'name', 'location', 'weather')
英文:

I have a model like this:

class Camper(models.Model):
    location = models.PointField()
    name = models.CharField(max_length=255)

and a viewset like this:

class CamperViewSet(viewsets.ModelViewSet):
...
    def retrieve(self, request, *args, **kwargs):
        """Retrieve a Camper instance."""
        show_weather = request.query_params.get('showWeather', False)
        instance = self.get_object()
        if show_weather:
            lat = instance.location.y
            lon = instance.location.x
            instance.weather = getWeatherFromLatLon(lat, lon)

        serializer = self.get_serializer(instance)
        return Response(serializer.data)

So when I request /api/campers/8?showWeather=true I make another request in my view to get the weather from the current position.

How do I add it to my serializer ? It's an optional field so I need to manage this and it's only used in /campers/id so it will not be used in list/create/put/etc

My serializer looks like this:

class CamperSerializer(serializers.ModelSerializer):

    camper_id = serializers.IntegerField(source='id')

    class Meta:
        model = Camper
        fields = ('camper_id', 'name', 'location')


</details>


# 答案1
**得分**: 1

你可以为`retrive`操作添加`custom serializer`。我称之为`CamperRetriveSerializer`。

在`CamperRetriveSerializer`内,你可以使用`SerializerMethodField`来定义数据库中不存在的字段。

并且,你想要检查请求中的参数`show_weather`,最好是将其值传递到`context`中,并在序列化器中获取它。

像这样:

```python
class CamperRetriveSerializer(serializers.ModelSerializer):
    
    weather = serializers.SerializerMethodField()
    camper_id = serializers.IntegerField(source='id')
    
    def get_weather(self, obj):
        show_weather = self.context.get('show_weather')
        if show_weather:
            lat = obj.location.y
            lon = obj.location.x
            return getWeatherFromLatLon(lat, lon)

        # 如果在请求中没有show_weather,则定义默认值
        return ''

    class Meta:
        model = Camper
        fields = ('camper_id', 'name', 'location', 'weather')


class CamperViewSet(viewsets.ModelViewSet):
    ...

    def retrieve(self, request, *args, **kwargs):
        """Retrieve a Camper instance."""
        instance = self.get_object()
        show_weather = self.request.query_params.get('showWeather', False)
        context = {
            'show_weather': show_weather
        }
        serializer = CamperRetriveSerializer(instance, context=context)
        return Response(serializer.data)
英文:

you can add custom serializer for retrive only todo it. I called CamperRetriveSerializer.

Inside CamperRetriveSerializer, you can use SerializerMethodField for define field not have in database.

And you want check param show_weather from request, best is pass value of it to context and get it in serializer.

Like this:

    class CamperRetriveSerializer(serializers.ModelSerializer):
    
        weather = serializers.SerializerMethodField()
        camper_id = serializers.IntegerField(source=&#39;id&#39;)
    
        def get_weather(self, obj):
            show_weather = self.context.get(&#39;show_weather&#39;)
            if show_weather:
                lat = obj.location.y
                lon = obj.location.x
                return getWeatherFromLatLon(lat, lon)
    
            # define default value if not show_weather in this
            return &#39;&#39;
    
        class Meta:
            model = Camper
            fields = (&#39;camper_id&#39;, &#39;name&#39;, &#39;location&#39;, &#39;weather&#39;)
    
    
    
    class CamperViewSet(viewsets.ModelViewSet):
    ...
    
    
        def retrieve(self, request, *args, **kwargs):
            &quot;&quot;&quot;Retrieve a Camper instance.&quot;&quot;&quot;
            instance = self.get_object()
            show_weather = self.request.query_params.get(&#39;showWeather&#39;, False)
            context = {
                &#39;show_weather&#39;: show_weather
            }
            serializer = CamperRetriveSerializer(instance, context=context)
            return Response(serializer.data)

答案2

得分: 0

你可以为此使用两种不同的序列化器。

class CamperViewSet(viewsets.ModelViewSet):
    serializer_class = CamperSerializer

    def get_serializer_class(self):
        serializer_class = self.serialzier_class
        if self.request.method == &#39;GET&#39;:
            serializer_class = CamperSerializerGet
        return serializer_class

# 用于GET请求的序列化器
class CamperSerializerGet(serializers.ModelSerializer):
    weather = serialziers.SerializerMethodField()
    camper_id = serializers.IntegerField(source=&#39;id&#39;)

    def get_weather(self, obj):
        return obj.weather    

    class Meta:
        model = Camper
        fields = (&#39;camper_id&#39;, &#39;name&#39;, &#39;location&#39;, &#39;weather&#39;)

# 用于其他请求的序列化器
class CamperSerializer(serializers.ModelSerializer):
    camper_id = serializers.IntegerField(source=&#39;id&#39;)

    class Meta:
        model = Camper
        fields = (&#39;camper_id&#39;, &#39;name&#39;, &#39;location&#39;)
英文:

You can use two different serializers for this.

class CamperViewSet(viewsets.ModelViewSet):
    serializer_class = CamperSerializer

    def get_serializer_class(self):
        serializer_class = self.serialzier_class
        if self.request.method == &#39;GET&#39;:
            serializer_class = CamperSerializerGet
        return serializer_class

#Serializer for GET request
class CamperSerializerGet(serializers.ModelSerializer):
    weather = serialziers.SerializerMethodField()
    camper_id = serializers.IntegerField(source=&#39;id&#39;)

    def get_weather(self, obj):
        return obj.weather    

    class Meta:
        model = Camper
        fields = (&#39;camper_id&#39;, &#39;name&#39;, &#39;location&#39;, &#39;weather&#39;)

#For other requests call this
class CamperSerializer(serializers.ModelSerializer):

    camper_id = serializers.IntegerField(source=&#39;id&#39;)

    class Meta:
        model = Camper
        fields = (&#39;camper_id&#39;, &#39;name&#39;, &#39;location&#39;)

huangapple
  • 本文由 发表于 2023年2月14日 02:15:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/75439749.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定