web-dev-qa-db-ja.com

Django Rest FrameworkとJSONField

JSONField でDjangoモデルが与えられた場合、 Django Rest Framework を使用してモデルをシリアライズおよびデシリアライズする正しい方法は何ですか?

私はすでにカスタム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)

しかし、partial=Trueを使用してモデルを更新しようとすると、JSONFieldオブジェクトのすべてのフロートが文字列になります。

49
Tzach

Django Rest Framework> = 3.3を使用している場合、JSONFieldシリアライザーは 現在含まれています です。これが正しい方法です。

Django Rest Framework <3.0を使用している場合は、gzeroneの答えを参照してください。

DRF 3.0-3.2を使用していて、アップグレードできず、バイナリデータをシリアル化する必要がない場合は、次の手順に従ってください。

最初にフィールドクラスを宣言します。

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

そして、次のようにフィールドをモデルに追加します

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

また、バイナリデータをシリアル化する必要がある場合は、いつでもコピーできます 公式リリースコード

60
Mark Chackerian

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.
18
gzerone

serializers.WritableFieldは非推奨です。これは動作します:

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
5
David Dehghan

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

正常に動作します。 Django 1.8でDRF 3.15とJSONFieldsを使用する

4
jonalvarezz

記録に関しては、PostgreSQLを使用していて、モデルフィールドがaDjango.contrib.postgres.JSONField

私はPostgreSQL 9.4、Django 1.9、およびDjango =REST Framework 3.3.2。

以前にここにリストされている他のソリューションのいくつかを使用しましたが、その余分なコードを削除できました。

モデル例:

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

シリアライザーの例:

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

サンプルビュー:

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']
4
Scott Smith

JSONコンテンツの最初のレベルのスタイル(ListまたはDict)を知っている場合にのみ、DRFビルトイン DictField または ListField を使用できます。

例:

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

ネストされたコンテンツを含め、GET/PUT/PATCH/POSTで正常に動作します。

4

Mysqlを使用している場合(他のデータベースでは試していません)、DRFの新しいJSONFieldとMark Chackerianが推奨するJSONSerializerFieldの両方を使用すると、jsonは{u'foo': u'bar'}文字列として保存されます。 {"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)
1
Daniel Levinson

助けてくれてありがとう。これは私が最終的にそれをレンダリングするために使用するコードです

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',)
1
antikytheraton

リクエストからデータをシリアル化するには、serializers.ModelSerializerを使用できます

serializers.py

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

views.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
1
Albin David

DRFはバイナリデータ用の組み込みフィールド「JSONField」を提供しますが、JSONペイロードは「binary」フラグをTrueに設定してからutf-8に変換し、JSONペイロードをロードする場合にのみ検証されます。 JSONFieldを作成した場合でも、エラーなしで両方を検証し、両方を検証します

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

MysqlのJSONFieldが必要な場合、これはDjango-mysqlで行われ、シリアライザーは先日[1]に修正されましたが、まだリリースされていません。

[1] https://github.com/adamchainz/Django-mysql/issues/35

setting.py

追加:

    'Django_mysql',

models.py

from Django_mysql.models import JSONField

class Something(models.Model):
(...)
    parameters = JSONField()
0
Sérgio