Подтвердить что ты не робот

Django Rest Framework и JSONField

Учитывая модель Django с JSONField, что является правильным способом сериализации и десериализации ее с помощью Django Rest Framework?

Я уже пробовал разбивать пользовательский serializers.WritableField и переопределять to_native и from_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 становятся строками.

4b9b3361

Ответ 1

Если вы используете 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()

И если вам нужно сериализовать двоичные данные, вы всегда можете скопировать официальный код выпуска

Ответ 2

В 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.

Ответ 3

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

Ответ 4

Mark Chackerian script не работал у меня, я должен был заставить json transform:

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

Прекрасно работает. Использование DRF 3.15 и JSONFields в Django 1.8

Ответ 5

Если и только если вы знаете стиль вашего уровня JSON первого уровня (List или Dict), вы можете использовать встроенный DRF DictField или ListField.

Пример:

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

Он отлично работает с GET/PUT/PATCH/POST, включая вложенное содержимое.

Ответ 6

Для записи это "просто работает" теперь, если вы используете PostgreSQL, а поле вашей модели - django.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']

Ответ 7

Если вы используете mysql (не пробовали с другими базами данных), используя как DRF new 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)

Ответ 8

Спасибо за помощь. Это код, который я, наконец, использую для его рендеринга.

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

Ответ 9

Если вы хотите JSONField для mysql, это делается в django-mysql, и сериализатор был исправлен некоторое время назад [1], еще не выпущен.

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

setting.py

добавить:

    'django_mysql',

models.py

from django_mysql.models import JSONField

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

Ответ 10

DRF дает нам встроенное поле 'JSONField' для двоичных данных, но полезная нагрузка JSON проверяется только тогда, когда вы устанавливаете флаг 'двоичный' True, затем он конвертируется в utf-8 и загружает полезную нагрузку JSON, иначе он обрабатывает их только как строку (если недопустимый json отправлено) или json и подтвердите оба без ошибок, даже если вы указали JSONField

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

Ответ 11

Для сериализации данных из запроса вы можете использовать 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,)

    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

    #Not tried this function but it will work
    [from_drf_documentation][1]
    def djson(self,request,format=None):
        stream = io.BytesIO(json)
        data = JSONParser().parse(stream)
        serializer = FinalSerializer(data=data)
        serializer.is_valid()
        serializer.validated_data