英文:
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='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)
    
            # define default value if not show_weather in this
            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)
答案2
得分: 0
你可以为此使用两种不同的序列化器。
class CamperViewSet(viewsets.ModelViewSet):
    serializer_class = CamperSerializer
    def get_serializer_class(self):
        serializer_class = self.serialzier_class
        if self.request.method == 'GET':
            serializer_class = CamperSerializerGet
        return serializer_class
# 用于GET请求的序列化器
class CamperSerializerGet(serializers.ModelSerializer):
    weather = serialziers.SerializerMethodField()
    camper_id = serializers.IntegerField(source='id')
    def get_weather(self, obj):
        return obj.weather    
    class Meta:
        model = Camper
        fields = ('camper_id', 'name', 'location', 'weather')
# 用于其他请求的序列化器
class CamperSerializer(serializers.ModelSerializer):
    camper_id = serializers.IntegerField(source='id')
    class Meta:
        model = Camper
        fields = ('camper_id', 'name', 'location')
英文:
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 == 'GET':
            serializer_class = CamperSerializerGet
        return serializer_class
#Serializer for GET request
class CamperSerializerGet(serializers.ModelSerializer):
    weather = serialziers.SerializerMethodField()
    camper_id = serializers.IntegerField(source='id')
    def get_weather(self, obj):
        return obj.weather    
    class Meta:
        model = Camper
        fields = ('camper_id', 'name', 'location', 'weather')
#For other requests call this
class CamperSerializer(serializers.ModelSerializer):
    camper_id = serializers.IntegerField(source='id')
    class Meta:
        model = Camper
        fields = ('camper_id', 'name', 'location')
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论