Django Rest Framework在POST中接收主键值并将模型对象作为嵌套序列化器返回

Cri*_*jas 6 python django serialization json django-rest-framework

我不完全确定我的问题的标题是我想要的那样具体,但事实是这样的:

我有一个HyperlinkedModelSerializer看起来像这样:

class ParentArrivalSerializer(serializers.HyperlinkedModelSerializer):
    carpool = SchoolBuildingCarpoolSerializer()

    class Meta:
        model = ParentArrival
Run Code Online (Sandbox Code Playgroud)

如您所见,它carpool被定义为嵌套的序列化器对象,我想要的是能够以ParentArrival这种方式创建一个POST请求(数据为application/json):

{
    ...
    "carpool": "http://localhost:8000/api/school-building-carpools/10/"
    ...
}
Run Code Online (Sandbox Code Playgroud)

并以这种方式接收数据:

{
    "carpool": {
        "url": "http://localhost:8000/api/school-building-carpools/10/"
        "name": "Name of the carpool",
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上,我正在寻找一种处理嵌套序列化程序的方法,而不必在POST请求中将数据作为对象(但在这种情况下为id或url)发送,但接收对象嵌套在序列化响应中.

dka*_*mer 12

我对以前的解决方案感到满意,但我决定重新审视,我认为我有另一种解决方案可以完全满足您的需求.

基本上,您需要创建自己的自定义字段,并且只需覆盖该to_representation方法:

class CarpoolField(serializers.PrimaryKeyRelatedField):
    def to_representation(self, value):
        pk = super(CarpoolField, self).to_representation(value)
        try:
           item = ParentArrival.objects.get(pk=pk)
           serializer = CarpoolSerializer(item)
           return serializer.data
        except ParentArrival.DoesNotExist:
           return None

    def get_choices(self, cutoff=None):
        queryset = self.get_queryset()
        if queryset is None:
            return {}

        return OrderedDict([(item.id, str(item)) for item in queryset])

class ParentArrivalSerializer(serializers.HyperlinkedModelSerializer):
    carpool = CarpoolField(queryset=Carpool.objects.all())

    class Meta:
        model = ParentArrival
Run Code Online (Sandbox Code Playgroud)

这将允许您发布

{
     "carpool": 10
}
Run Code Online (Sandbox Code Playgroud)

得到:

{
    "carpool": {
        "url": "http://localhost:8000/api/school-building-carpools/10/"
        "name": "Name of the carpool",
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)


ram*_*win 10

重写to_representation方法怎么样?

class YourSerializer(serializers.ModelSerializer):

    class Meta:
        model = ModelClass
        fields = ["id", "foreignkey"]

    def to_representation(self, instance):
        data = super(YourSerializer, self).to_representation(instance)
        data['foreignkey'] = YourNestedSerializer(instance.foreignkey).data
        return data
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案!它更简单、更干净,因为它不需要创建新字段并更改 API 请求。太感谢了! (3认同)

Deq*_*qun 10

这很简单。如您所知,Django appends "_id" to the field name在ModelClass中,您可以在SerializerClass中实现它,也可以实现原始文件。您要做的就是这样

class ParentArrivalSerializer(serializers.HyperlinkedModelSerializer):
    # ...
    carpool_id = serializers.IntegerField(write_only=True)
    carpool = SchoolBuildingCarpoolSerializer(read_only=True)
    # ...
    class Meta:
        fields = ('carpool_id', 'carpool', ...)
Run Code Online (Sandbox Code Playgroud)

并用于carpool_idPOST请求。

  • 谢谢!清晰明了。我还必须在类Meta的“字段”列表中添加“ carpool_id”,并且使用了serializers.UUIDField,因为我的ID是UUID,而不是整数。它可以工作,我喜欢这个答案,因为它可以直接在数据库中工作,而我不必更改任何端点。 (2认同)