简体   繁体   English

Django Rest 框架和 JSONField

[英]Django Rest Framework and JSONField

Given a Django model with a JSONField , what is the correct way of serializing and deserializing it using Django Rest Framework ?给定一个带有JSONField的 Django 模型,使用Django Rest Framework对其进行序列化和反序列化的正确方法是什么?

I've already tried crating a custom serializers.WritableField and overriding to_native and from_native :我已经尝试过创建自定义serializers.WritableField并覆盖to_nativefrom_native

from json_field.fields import JSONEncoder, JSONDecoder
from rest_framework import serializers

class JSONFieldSerializer(serializers.WritableField):
    def to_native(self, obj):
    return json.dumps(obj, cls = JSONEncoder)

    def from_native(self, data):
        return json.loads(data, cls = JSONDecoder)

But when I try to updating the model using partial=True , all the floats in the JSONField objects become strings.但是当我尝试使用partial=True更新模型时,JSONField 对象中的所有浮点数都变成了字符串。

If you're using Django Rest Framework >= 3.3, then the JSONField serializer is now included .如果您使用的是 Django Rest Framework >= 3.3,那么现在包含JSONField 序列化程序。 This is now the correct way.这是现在正确的方法。

If you're using Django Rest Framework < 3.0, then see gzerone's answer.如果您使用的是 Django Rest Framework < 3.0,请参阅 gzerone 的答案。

If you're using DRF 3.0 - 3.2 AND you can't upgrade AND you don't need to serialize binary data, then follow these instructions.如果您使用的是 DRF 3.0 - 3.2 并且您无法升级并且您不需要序列化二进制数据,请按照这些说明进行操作。

First declare a field class:首先声明一个字段类:

from rest_framework import serializers

class JSONSerializerField(serializers.Field):
    """ Serializer for JSONField -- required to make field writable"""
    def to_internal_value(self, data):
        return data
    def to_representation(self, value):
        return value

And then add in the field into the model like然后在字段中添加到模型中

class MySerializer(serializers.ModelSerializer):
    json_data = JSONSerializerField()

And, if you do need to serialize binary data, you can always the copy official release code而且,如果你确实需要序列化二进制数据,你可以随时复制官方发布的代码

In 2.4.x:在 2.4.x 中:

from rest_framework import serializers # get from https://gist.github.com/rouge8/5445149

class WritableJSONField(serializers.WritableField):
    def to_native(self, obj):
        return obj


class MyModelSerializer(serializers.HyperlinkedModelSerializer):
    my_json_field = WritableJSONField() # you need this.

serializers.WritableField is deprecated. serializers.WritableField 已弃用。 This works:这有效:

from rest_framework import serializers
from website.models import Picture


class PictureSerializer(serializers.HyperlinkedModelSerializer):
    json = serializers.SerializerMethodField('clean_json')

    class Meta:
        model = Picture
        fields = ('id', 'json')

    def clean_json(self, obj):
        return obj.json

Mark Chackerian script didn't work for me, I'd to force the json transform: Mark Chackerian 脚本对我不起作用,我会强制进行 json 转换:

import json

class JSONSerializerField(serializers.Field):
    """ Serializer for JSONField -- required to make field writable"""

    def to_internal_value(self, data):
        json_data = {}
        try:
            json_data = json.loads(data)
        except ValueError, e:
            pass
        finally:
            return json_data
    def to_representation(self, value):
        return value

Works fine.工作正常。 Using DRF 3.15 and JSONFields in Django 1.8在 Django 1.8 中使用 DRF 3.15 和 JSONFields

If and only if you know the first-level style of your JSON content (List or Dict), you can use DRF builtin DictField or ListField .当且仅当您知道 JSON 内容的一级样式(List 或 Dict)时,您才能使用 DRF 内置DictFieldListField

Ex:前任:

class MyModelSerializer(serializers.HyperlinkedModelSerializer):
    my_json_field = serializers.DictField()

It works fine, with GET/PUT/PATCH/POST , including with nested contents.它工作正常,使用GET/PUT/PATCH/POST ,包括嵌套内容。

For the record, this "just works" now if you are using PostgreSQL, and your model field is a django.contrib.postgres.JSONField .作为记录,如果您使用的是 PostgreSQL,并且您的模型字段是django.contrib.postgres.JSONField ,那么这现在“有效”。

I'm on PostgreSQL 9.4, Django 1.9, and Django REST Framework 3.3.2.我使用的是 PostgreSQL 9.4、Django 1.9 和 Django REST Framework 3.3.2。

I have previously used several of the other solutions listed here, but was able to delete that extra code.我以前使用过这里列出的其他几个解决方案,但能够删除那些额外的代码。

Example Model:示例模型:

class Account(models.Model):
    id = UUIDField(primary_key=True, default=uuid_nodash)
    data = JSONField(blank=True, default="")

Example Serializer:示例序列化程序:

class AccountSerializer(BaseSerializer):
    id = serializers.CharField()
    class Meta:
        model = Account
        fields = ('id','data')

Example View:示例视图:

class AccountViewSet(
    viewsets.GenericViewSet,
    mixins.CreateModelMixin,      
    mixins.RetrieveModelMixin,
    mixins.ListModelMixin,
    mixins.UpdateModelMixin,
    mixins.DestroyModelMixin
): 
    model = Account
    queryset = Account.objects.all()
    serializer_class = AccountSerializer
    filter_fields = ['id', 'data']

Thanks by the help.感谢帮助。 This is the code i finally use for render it这是我最终用来渲染它的代码

class JSONSerializerField(serializers.Field):
    """Serializer for JSONField -- required to make field writable"""

    def to_representation(self, value):
        json_data = {}
        try:
            json_data = json.loads(value)
        except ValueError as e:
            raise e
        finally:
            return json_data

    def to_internal_value(self, data):
        return json.dumps(data)

class AnyModelSerializer(serializers.ModelSerializer):
    field = JSONSerializerField()

    class Meta:
        model = SomeModel
        fields = ('field',)

If you're using mysql (haven't tried with other databases), using both DRF's new JSONField and Mark Chackerian's suggested JSONSerializerField will save the json as a {u'foo': u'bar'} string.如果您使用的是 mysql(尚未尝试使用其他数据库),则同时使用 DRF 的新JSONField和 Mark Chackerian 建议的JSONSerializerField会将 json 保存为{u'foo': u'bar'}字符串。 If you rather save it as {"foo": "bar"} , this works for me:如果你更愿意将它保存为{"foo": "bar"} ,这对我有用:

import json

class JSONField(serializers.Field):
    def to_representation(self, obj):
        return json.loads(obj)

    def to_internal_value(self, data):
        return json.dumps(data)

DRF gives us inbuilt field 'JSONField' for binary data, but JSON payload is verified only when you set 'binary' flag True then it convert into utf-8 and load the JSON payload, else it only treat them as string(if invalid json is sent) or json and validate both without error even though you cretaed JSONField DRF 为我们提供了用于二进制数据的内置字段 'JSONField',但是只有当您设置 'binary' 标志为 True 时才会验证 JSON 有效负载,然后它会转换为 utf-8 并加载 JSON 有效负载,否则它只会将它们视为字符串(如果无效的 json发送) 或 json 并验证两者都没有错误,即使您创建了 JSONField

class JSONSerializer(serializers.ModelSerializer):
    """
    serializer for JSON
    """
    payload = serializers.JSONField(binary=True)

To serialize a data from a request you can use the serializers.ModelSerializer要从请求序列化数据,您可以使用 serializers.ModelSerializer

serializers.py序列化程序.py

from rest_framwork import serializers
class FinalSerializer(serializers.ModelSerializer):
class Meta:
    model=Student
    fields='__all__'

views.py视图.py

import io
from yourappname.serializers import FinalSerializer #replace your app name
from rest_framework.parsers import JSONParser
from rest_framework.views import APIView
from rest_framework.parsers import JSONParser,MultiPartParser,FormParser
from rest_framework.response import Response


class DataList(APIView):


    parser_classes = (JSONParser,MultiPartParser,FormParser) #If you are using postman
    renderer_classes = (JSONRenderer,)
    #Serialize
    def get(self,request,format=None):
        all_data=Student.objects.all()
        serializer=FinalSerializer(all_data,many=True)
        return Response(serializer.data)#Will return serialized json data,makes sure you have data in your model
    #Deserialize
    #Not tried this function but it will work
    #from django documentation
    def djson(self,request,format=None):
        stream = io.BytesIO(json)
        data = JSONParser().parse(stream)
        serializer = FinalSerializer(data=data)
        serializer.is_valid()
        serializer.validated_data

If you want JSONField for mysql this is done in django-mysql and serializer was fixed some day ago [1], is not yet in any release.如果你想要用于 mysql 的 JSONField,这是在 django-mysql 中完成的,并且序列化程序在几天前已经修复 [1],目前还没有任何版本。

[1] https://github.com/adamchainz/django-mysql/issues/353 [1] https://github.com/adamchainz/django-mysql/issues/353

setting.py设置.py

add:添加:

    'django_mysql',

models.py模型.py

from django_mysql.models import JSONField

class Something(models.Model):
(...)
    parameters = JSONField()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM