with instalar framework español django django-rest-framework

instalar - django rest framework with django 2



Django Rest Framework: devuelve dinámicamente subconjunto de campos (6)

Configurar una nueva clase de serializador de paginación

from rest_framework import pagination, serializers class DynamicFieldsPaginationSerializer(pagination.BasePaginationSerializer): """ A dynamic fields implementation of a pagination serializer. """ count = serializers.Field(source=''paginator.count'') next = pagination.NextPageField(source=''*'') previous = pagination.PreviousPageField(source=''*'') def __init__(self, *args, **kwargs): """ Override init to add in the object serializer field on-the-fly. """ fields = kwargs.pop(''fields'', None) super(pagination.BasePaginationSerializer, self).__init__(*args, **kwargs) results_field = self.results_field object_serializer = self.opts.object_serializer_class if ''context'' in kwargs: context_kwarg = {''context'': kwargs[''context'']} else: context_kwarg = {} if fields: context_kwarg.update({''fields'': fields}) self.fields[results_field] = object_serializer(source=''object_list'', many=True, **context_kwarg) # Set the pagination serializer setting REST_FRAMEWORK = { # [...] ''DEFAULT_PAGINATION_SERIALIZER_CLASS'': ''DynamicFieldsPaginationSerializer'', }

Hacer serializador dinámico

from rest_framework import serializers class DynamicFieldsModelSerializer(serializers.ModelSerializer): """ A ModelSerializer that takes an additional `fields` argument that controls which fields should be displayed. See: http://tomchristie.github.io/rest-framework-2-docs/api-guide/serializers """ def __init__(self, *args, **kwargs): # Don''t pass the ''fields'' arg up to the superclass fields = kwargs.pop(''fields'', None) # Instantiate the superclass normally super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) if fields: # Drop any fields that are not specified in the `fields` argument. allowed = set(fields) existing = set(self.fields.keys()) for field_name in existing - allowed: self.fields.pop(field_name) # Use it class MyPonySerializer(DynamicFieldsModelSerializer): # [...]

Por último, use una mezcla de homemage para sus APIViews

class DynamicFields(object): """A mixins that allows the query builder to display certain fields""" def get_fields_to_display(self): fields = self.request.GET.get(''fields'', None) return fields.split('','') if fields else None def get_serializer(self, instance=None, data=None, files=None, many=False, partial=False, allow_add_remove=False): """ Return the serializer instance that should be used for validating and deserializing input, and for serializing output. """ serializer_class = self.get_serializer_class() context = self.get_serializer_context() fields = self.get_fields_to_display() return serializer_class(instance, data=data, files=files, many=many, partial=partial, allow_add_remove=allow_add_remove, context=context, fields=fields) def get_pagination_serializer(self, page): """ Return a serializer instance to use with paginated data. """ class SerializerClass(self.pagination_serializer_class): class Meta: object_serializer_class = self.get_serializer_class() pagination_serializer_class = SerializerClass context = self.get_serializer_context() fields = self.get_fields_to_display() return pagination_serializer_class(instance=page, context=context, fields=fields) class MyPonyList(DynamicFields, generics.ListAPIView): # [...]

Solicitud

Ahora, cuando solicita un recurso, puede agregar fields parámetros para mostrar solo los campos especificados en url. /?fields=field1,field2

Puede encontrar un recordatorio aquí: https://gist.github.com/Kmaschta/e28cf21fb3f0b90c597a

Problema

Como se recomienda en las mejores prácticas de blogpost para diseñar una API RESTful pragmática , me gustaría agregar un parámetro de consulta de fields a una API basada en el Marco de descanso de Django que permita al usuario seleccionar solo un subconjunto de campos por recurso.

Ejemplo

Serializador:

class IdentitySerializer(serializers.HyperlinkedModelSerializer): class Meta: model = models.Identity fields = (''id'', ''url'', ''type'', ''data'')

Una consulta regular devolvería todos los campos.

GET /identities/

[ { "id": 1, "url": "http://localhost:8000/api/identities/1/", "type": 5, "data": "John Doe" }, ... ]

Una consulta con el parámetro de fields solo debe devolver un subconjunto de los campos:

GET /identities/?fields=id,data

[ { "id": 1, "data": "John Doe" }, ... ]

Una consulta con campos no válidos debe ignorar los campos no válidos o lanzar un error de cliente.

Gol

¿Es esto posible fuera de la caja de alguna manera? Si no es así, ¿cuál es la forma más sencilla de implementar esto? ¿Hay un paquete de terceros alrededor que hace esto ya?


serializers.py

class DynamicFieldsSerializerMixin(object): def __init__(self, *args, **kwargs): # Don''t pass the ''fields'' arg up to the superclass fields = kwargs.pop(''fields'', None) # Instantiate the superclass normally super(DynamicFieldsSerializerMixin, self).__init__(*args, **kwargs) if fields is not None: # Drop any fields that are not specified in the `fields` argument. allowed = set(fields) existing = set(self.fields.keys()) for field_name in existing - allowed: self.fields.pop(field_name) class UserSerializer(DynamicFieldsSerializerMixin, serializers.HyperlinkedModelSerializer): password = serializers.CharField( style={''input_type'': ''password''}, write_only=True ) class Meta: model = User fields = (''id'', ''username'', ''password'', ''email'', ''first_name'', ''last_name'') def create(self, validated_data): user = User.objects.create( username=validated_data[''username''], email=validated_data[''email''], first_name=validated_data[''first_name''], last_name=validated_data[''last_name''] ) user.set_password(validated_data[''password'']) user.save() return user

vistas.py

class DynamicFieldsViewMixin(object): def get_serializer(self, *args, **kwargs): serializer_class = self.get_serializer_class() fields = None if self.request.method == ''GET'': query_fields = self.request.QUERY_PARAMS.get("fields", None) if query_fields: fields = tuple(query_fields.split('','')) kwargs[''context''] = self.get_serializer_context() kwargs[''fields''] = fields return serializer_class(*args, **kwargs) class UserList(DynamicFieldsViewMixin, ListCreateAPIView): queryset = User.objects.all() serializer_class = UserSerializer


Dicha funcionalidad que hemos proporcionado en drf_tweaks / control-over-serial--fields .

Si utiliza nuestros serializadores, todo lo que necesita es pasar los ?fields=x,y,z Parámetro ?fields=x,y,z en la consulta.


Esta funcionalidad está disponible en un paquete de terceros .

pip install djangorestframework-queryfields

Declara tu serializador de esta manera:

from rest_framework.serializers import ModelSerializer from drf_queryfields import QueryFieldsMixin class MyModelSerializer(QueryFieldsMixin, ModelSerializer): ...

Entonces los campos ahora se pueden especificar (del lado del cliente) usando argumentos de consulta:

GET /identities/?fields=id,data

El filtrado de exclusión también es posible, por ejemplo, para devolver todos los campos excepto id:

GET /identities/?fields!=id

descargo de responsabilidad: soy el autor / mantenedor.


Puede anular el método serializador __init__ y establecer el atributo de los fields forma dinámica, según los parámetros de consulta. Puede acceder al contexto de la request el contexto, pasado al serializador.

Aquí creé un mixin reutilizable, que realiza la modificación de fields dinámicos.

from rest_framework import serializers class DynamicFieldsModelSerializer(serializers.ModelSerializer): """ A ModelSerializer that takes an additional `fields` argument that controls which fields should be displayed. """ def __init__(self, *args, **kwargs): # Instantiate the superclass normally super(DynamicFieldsModelSerializer, self).__init__(*args, **kwargs) fields = self.context[''request''].QUERY_PARAMS.get(''fields'') if fields: fields = fields.split('','') # Drop any fields that are not specified in the `fields` argument. allowed = set(fields) existing = set(self.fields.keys()) for field_name in existing - allowed: self.fields.pop(field_name) class UserSerializer(DynamicFieldsModelSerializer, serializers.HyperlinkedModelSerializer): class Meta: model = User fields = (''url'', ''username'', ''email'')


Puede probar Dynamic REST , que es compatible con campos dinámicos (inclusión, exclusión), objetos incrustados / cargados, filtrado, ordenamiento, paginación y más.