it-swarm.com.de

Django Rest Framework und JSONField

Anhand eines Django-Modells mit einem JSONField - Wie kann man es mit Django Rest Framework richtig serialisieren und deserialisieren?

Ich habe bereits versucht, einen benutzerdefinierten serializers.WritableField zu erstellen und to_native und from_native zu überschreiben:

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)

Wenn ich jedoch versuche, das Modell mithilfe von partial=True zu aktualisieren, werden alle Floats in den JSONField-Objekten zu Strings.

46
Tzach

Wenn Sie Django Rest Framework> = 3.3 verwenden, ist der JSONField-Serialisierer jetzt enthalten . Dies ist jetzt der richtige Weg.

Wenn Sie Django Rest Framework <3.0 verwenden, lesen Sie die Antwort von gzerone.

Wenn Sie DRF 3.0 - 3.2 UND verwenden, können Sie kein Upgrade durchführen UND Sie müssen keine binären Daten serialisieren. Befolgen Sie dann diese Anweisungen.

Zuerst deklarieren Sie eine Feldklasse:

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

Und dann füge ich das Feld gerne in das Modell ein

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

Und wenn Sie binäre Daten serialisieren müssen, können Sie immer die Kopie offiziellen Freigabecode

58
Mark Chackerian

In 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 ist veraltet. Das funktioniert:

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 Skript funktionierte nicht für mich, ich würde die Json-Transformation erzwingen:

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

Funktioniert gut. Verwenden von DRF 3.15 und JSONFields in Django 1.8

4
jonalvarezz

Für das Protokoll funktioniert das "nur" jetzt, wenn Sie PostgreSQL verwenden und Ihr Modellfeld ein Django.contrib.postgres.JSONField ist. 

Ich bin in PostgreSQL 9.4, Django 1.9 und Django REST Framework 3.3.2.

Ich habe bereits einige der anderen hier aufgeführten Lösungen verwendet, konnte diesen zusätzlichen Code jedoch löschen.

Beispielmodell:

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

Beispiel Serializer:

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

Beispielansicht:

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

Wenn und nur wenn Sie den First-Level-Stil Ihres JSON-Inhalts (List oder Dict) kennen, können Sie DRF-eingebaute DictField oder ListField verwenden.

Ex: 

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

Es funktioniert gut mit GET/PUT/PATCH/POST, auch mit verschachtelten Inhalten.

4

Wenn Sie mysql verwenden (haben Sie es nicht mit anderen Datenbanken versucht), werden sowohl die neue JSONField von DRF als auch der von Mark Chackerian vorgeschlagene JSONSerializerField als j{u'foo': u'bar'}-String gespeichert. Wenn Sie es eher als {"foo": "bar"} speichern, funktioniert dies für mich :

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

Danke der hilfe Dies ist der Code, den ich schließlich zum Rendern benutze

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

Um Daten aus einer Anfrage zu serialisieren, können Sie den Serialisierer.ModelSerializer verwenden

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
0
Albin David

DRF gibt uns das eingebaute Feld 'JSONField' für Binärdaten, aber JSON Die Payload wird nur überprüft, wenn Sie das 'binary' - Flag auf True setzen, dann in utf-8 konvertieren und die JSON-Payload laden, sonst nur Behandle sie als String (wenn ungültiger Json gesendet wird) oder Json und validiere beide ohne Fehler, obwohl Sie JSONField erstellt haben

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

Wenn Sie JSONField für mysql wollen, wird dies in Django-mysql gemacht, und der Serializer wurde vor einem Tag [1] behoben.

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

einstellung.py

hinzufügen: 

    'Django_mysql',

models.py

from Django_mysql.models import JSONField

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