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.