python - update - Django Rest Framework y JSONField
partial update django rest framework (10)
DRF nos da el campo incorporado ''JSONField'' para datos binarios, pero la carga útil JSON solo se verifica cuando configuramos el indicador ''binario'' True luego convierte a utf-8 y carga la carga JSON; de lo contrario, solo los trata como cadena (si no es válido) se envía) o json y valida ambos sin error a pesar de que cretaste JSONField
class JSONSerializer(serializers.ModelSerializer):
"""
serializer for JSON
"""
payload = serializers.JSONField(binary=True)
Dado un modelo de Django con un campo JSONField , ¿cuál es la forma correcta de serializarlo y deserializarlo usando Django Rest Framework ?
Ya he intentado crear un serializers.WritableField
personalizado. to_native
y from_native
to_native
y 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)
Pero cuando trato de actualizar el modelo usando partial=True
, todos los flotadores en los objetos JSONField se convierten en cadenas.
El guión de Mark Chackerian no funcionó para mí, forzaría la transformación 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
Funciona bien. Usando DRF 3.15 y JSONFields en Django 1.8
En 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.
Gracias por la ayuda. Este es el código que finalmente uso para renderizarlo
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'',)
Para el registro, esto "simplemente funciona" ahora si está usando PostgreSQL, y su campo de modelo es un django.contrib.postgres.JSONField
.
Estoy en PostgreSQL 9.4, Django 1.9 y Django REST Framework 3.3.2.
Anteriormente utilicé varias de las otras soluciones enumeradas aquí, pero pude eliminar ese código adicional.
Modelo de ejemplo:
class Account(models.Model):
id = UUIDField(primary_key=True, default=uuid_nodash)
data = JSONField(blank=True, default="")
Ejemplo de serializador:
class AccountSerializer(BaseSerializer):
id = serializers.CharField()
class Meta:
model = Account
fields = (''id'',''data'')
Vista de ejemplo:
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'']
Si desea JSONField para mysql esto se hace en django-mysql y el serializador se arregló hace un día [1], todavía no se encuentra en ninguna versión.
[1] https://github.com/adamchainz/django-mysql/issues/353
setting.py
añadir:
''django_mysql'',
models.py
from django_mysql.models import JSONField
class Something(models.Model):
(...)
parameters = JSONField()
Si está utilizando Django Rest Framework> = 3.3, entonces el serializador JSONField ahora está incluido . Esta es ahora la forma correcta.
Si está utilizando Django Rest Framework <3.0, entonces vea la respuesta de gzerone.
Si está utilizando DRF 3.0 - 3.2 Y no puede actualizar Y no necesita serializar datos binarios, siga estas instrucciones.
Primero declara una clase de campo:
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
Y luego agregue en el campo en el modelo como
class MySerializer(serializers.ModelSerializer):
json_data = JSONSerializerField()
Y, si necesita serializar datos binarios, siempre puede copiar el código de versión oficial
Si está utilizando mysql (no lo ha intentado con otras bases de datos), usar el nuevo JSONField
DRF y el JSONSerializerField sugerido por Mark Chackerian guardará el json como una {u''foo'': u''bar''}
. Si prefiere guardarlo como {"foo": "bar"}
, esto funciona para mí:
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)
Si, y solo si conoce el estilo de primer nivel de su contenido JSON (List o Dict), puede usar DRF DictField o ListField .
Ex:
class MyModelSerializer(serializers.HyperlinkedModelSerializer):
my_json_field = serializers.DictField()
Funciona bien, con GET/PUT/PATCH/POST
, incluso con contenido anidado.
serializers.WritableField está en desuso. Esto funciona:
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