update queryset password jsonfield framework create python django serialization django-rest-framework

python - queryset - listfield django rest framework



Django REST Framework-Serialización de campos opcionales (5)

A partir de los "es un terrible pirateo que se basa en detalles de implementación específicos de DRF y Django, pero funciona (al menos por ahora)", este es el enfoque que utilicé para incluir algunos datos de depuración adicionales en la respuesta de un método "crear" Implementación en un serializador:

def create(self, validated_data) # Actual model instance creation happens here... self.fields["debug_info"] = serializers.DictField(read_only=True) my_model.debug_info = extra_data return my_model

Este es un enfoque temporal que me permite usar la API navegable para mostrar algunos de los datos de respuesta sin procesar recibidos de un servicio remoto en particular durante el proceso de creación. En el futuro, me inclino a mantener esta capacidad, pero escóndala detrás de un indicador de "información de depuración de informes" en la solicitud de creación en lugar de devolver la información de nivel inferior de forma predeterminada.

Tengo un objeto que tiene campos opcionales. He definido mi serializador de esta manera:

class ProductSerializer(serializers.Serializer): code = serializers.Field(source="Code") classification = serializers.CharField(source="Classification", required=False)

thought que thought required=False haría el trabajo de omitir el campo si no existiera. Sin embargo, se menciona en la documentación que esto afecta la deserialización en lugar de la serialización.

Estoy recibiendo el siguiente error:

''Product'' object has no attribute ''Classification''

Lo que ocurre cuando intento acceder a .data de la instancia serializada. (¿No significa esto que es la deserialización que está provocando esto?)

Esto sucede para instancias que no tienen Classification . Si omito la Classification de la clase de serializador, funciona bien.

¿Cómo hago esto correctamente? Serializar un objeto con campos opcionales, es decir.


El método descrito a continuación hizo el trabajo por mí. Bastante simple, fácil y trabajado para mí.

Versión DRF usada = djangorestframework (3.1.0)

class test(serializers.Serializer): id= serializers.IntegerField() name=serializers.CharField(required=False,default=''some_default_value'')


Los serializadores están diseñados deliberadamente para usar un conjunto fijo de campos, de modo que usted no podría fácilmente abandonar una de las teclas.

Podría usar un SerializerMethodField para devolver el valor del campo o None si el campo no existe, o no podría usar los serializadores en absoluto y simplemente escribir una vista que devuelva la respuesta directamente.

La actualización para REST framework 3.0 serializer.fields se puede modificar en un serializador instanciado. Cuando se requieren clases dinámicas de serializador, probablemente sugiero que se modifiquen los campos en un método personalizado de Serializer.__init__() .


Para este propósito los serializadores tienen el argumento partial . Si cuando se inicializa el serializador, puede pasar partial=True . Si está utilizando genéricos o mixins, puede anular la función get_serializer siguiente manera:

def get_serializer(self, *args, **kwargs): kwargs[''partial''] = True return super(YOUR_CLASS, self).get_serializer(*args, **kwargs)

Y eso hará el truco.

Nota: Esto permite que todos los campos sean opcionales y no solo uno específico. Si solo desea información específica, puede anular el método (es decir, actualizar) y agregar validaciones de existencia para varios campos.


Django REST Framework 3.0+
Ahora se admiten campos dinámicos, consulte http://www.django-rest-framework.org/api-guide/serializers/#dynamically-modifying-fields : este enfoque define todos los campos en el serializador, y luego le permite Eliminar selectivamente los que no quieres.

O también puedes hacer algo como esto para un Serializador de modelos, en el que juegas con Meta.fields en el inicio del serializador:

class ProductSerializer(serializers.ModelSerializer): class Meta: model = Product fields = (''code'',) def __init__(self, *args, **kwargs): if SHOW_CLASSIFICATION: # add logic here for optional viewing self.Meta.fields = list(self.Meta.fields) self.Meta.fields.append(''classification'') super(ProductSerializer, self).__init__(*args, **kwargs)

Tendría que preguntarle a Tom si esta es la "manera correcta" ya que puede no encajar con el plan a largo plazo.

Django REST Framework <3.0
Intenta algo como esto:

class ProductSerializer(serializers.Serializer): ... classification = serializers.SerializerMethodField(''get_classification'') def get_classification(self, obj): return getattr(obj, ''classification'', None)

Serializadores Múltiples

Otro enfoque sería crear múltiples serializadores con diferentes conjuntos de campos. Un serializador hereda de otro y agrega campos adicionales. Luego, puede elegir el serializador apropiado en la vista con el método get_serializer_class . Este es un ejemplo real de cómo utilizo este enfoque para llamar a diferentes serializadores para presentar diferentes datos de usuario si el objeto de usuario es el mismo que el usuario de solicitud.

def get_serializer_class(self): """ An authenticated user looking at their own user object gets more data """ if self.get_object() == self.request.user: return SelfUserSerializer return UserSerializer

Eliminar campos de representación

Otro enfoque que he usado en contextos de seguridad es eliminar campos en el método to_representation . Definir un método como

def remove_fields_from_representation(self, representation, remove_fields): """ Removes fields from representation of instance. Call from .to_representation() to apply field-level security. * remove_fields: a list of fields to remove """ for remove_field in remove_fields: try: representation.pop(remove_field) except KeyError: # Ignore missing key -- a child serializer could inherit a "to_representation" method # from its parent serializer that applies security to a field not present on # the child serializer. pass

y luego en su serializador, llame a ese método como

def to_representation(self, instance): """ Apply field level security by removing fields for unauthorized users""" representation = super(ProductSerializer, self).to_representation(instance) if not permission_granted: # REPLACE WITH PERMISSION LOGIC remove_fields = (''classification'', ) self.remove_fields_from_representation(representation, remove_fields) return representation

Este enfoque es directo y flexible, pero tiene el costo de serializar campos que a veces no se muestran. Pero eso probablemente está bien.