Saltar al contenido

Django REST Framework – Serialización de campos opcionales

Después de de esta extensa compilación de datos hemos podido resolver este enigma que presentan algunos de nuestros usuarios. Te regalamos la solución y deseamos serte de gran ayuda.

Solución:

Marco REST de Django 3.0+

Los campos dinámicos ahora son compatibles, 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 elimine selectivamente los que no desee.

O también podría hacer algo como esto para un Model Serializer, donde juega 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)

Sin embargo, tendría que preguntarle a Tom si esta es la “manera correcta”, ya que puede no encajar con el plan a largo plazo.

Marco REST de Django <3.0

Prueba algo como esto:

class ProductSerializer(serializers.Serializer):
    ...
    classification = serializers.SerializerMethodField('get_classification')

    def get_classification(self, obj):
        return getattr(obj, 'classification', None)

Múltiples serializadores

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 get_serializer_class método. Aquí hay un ejemplo real de cómo uso este enfoque para llamar a diferentes serializadores para presentar diferentes datos de usuario si el objeto del usuario es el mismo que el usuario de la 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

Quitar campos de la representación

Otro enfoque que he usado en contextos de seguridad es eliminar campos en el to_representation método. Defina 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 sencillo y flexible, pero tiene el costo de serializar campos que a veces no se muestran. Pero probablemente esté bien.

Los serializadores están diseñados deliberadamente para usar un conjunto fijo de campos para que no pueda descartar fácilmente uno de los keys.

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

Actualización para el marco REST 3.0serializer.fields se puede modificar en un serializador instanciado. Cuando se requieren clases de serializador dinámico, probablemente sugiero modificar los campos de forma personalizada. Serializer.__init__() método.

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

Versión de DRF utilizada = djangorestframework (3.1.0)

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

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *