test - Agregar elemento raíz a la respuesta json(django-rest-framework)
modelserializer django rest framework (2)
Estoy tratando de determinar la mejor manera de agregar un elemento raíz a todas las respuestas json usando django y django-rest-framework.
Creo que agregar un renderizador personalizado es la mejor manera de lograr lo que quiero lograr y esto es lo que he propuesto hasta ahora:
from rest_framework.renderers import JSONRenderer
class CustomJSONRenderer(JSONRenderer):
#override the render method
def render(self, data, accepted_media_type=None, renderer_context=None):
#call super, as we really just want to mess with the data returned
json_str = super(CustomJSONRenderer, self).render(data, accepted_media_type, renderer_context)
root_element = ''contact''
#wrap the json string in the desired root element
ret = ''{%s: %s}'' % (root_element, json_str)
return ret
La parte complicada ahora es establecer dinámicamente el elemento root_element
basado en la vista desde la que se llama a render()
.
Cualquier sugerencia / consejos sería muy apreciada,
Aclamaciones
Para la posteridad, a continuación se encuentra la solución final. Ha crecido ligeramente desde el original, ya que ahora reformatea los resultados paginados también.
También debería haber especificado antes, que la razón para el elemento raíz JSON es para la integración con una solución de front-end Ember.
serializador
from rest_framework.serializers import ModelSerializer
from api.models import Contact
class ContactSerializer(ModelSerializer):
class Meta:
model = Contact
#define the resource we wish to use for the root element of the response
resource_name = ''contact''
fields = (''id'', ''first_name'', ''last_name'', ''phone_number'', ''company'')
renderizador:
from rest_framework.renderers import JSONRenderer
class CustomJSONRenderer(JSONRenderer):
"""
Override the render method of the django rest framework JSONRenderer to allow the following:
* adding a resource_name root element to all GET requests formatted with JSON
* reformatting paginated results to the following structure {meta: {}, resource_name: [{},{}]}
NB: This solution requires a custom pagination serializer and an attribute of ''resource_name''
defined in the serializer
"""
def render(self, data, accepted_media_type=None, renderer_context=None):
response_data = {}
#determine the resource name for this request - default to objects if not defined
resource = getattr(renderer_context.get(''view'').get_serializer().Meta, ''resource_name'', ''objects'')
#check if the results have been paginated
if data.get(''paginated_results''):
#add the resource key and copy the results
response_data[''meta''] = data.get(''meta'')
response_data[resource] = data.get(''paginated_results'')
else:
response_data[resource] = data
#call super to render the response
response = super(CustomJSONRenderer, self).render(response_data, accepted_media_type, renderer_context)
return response
paginación:
from rest_framework import pagination, serializers
class CustomMetaSerializer(serializers.Serializer):
next_page = pagination.NextPageField(source=''*'')
prev_page = pagination.PreviousPageField(source=''*'')
record_count = serializers.Field(source=''paginator.count'')
class CustomPaginationSerializer(pagination.BasePaginationSerializer):
# Takes the page object as the source
meta = CustomMetaSerializer(source=''*'')
results_field = ''paginated_results''
Estoy seguro de poder despertarme el 95% del camino.
Personalmente, quería agregar metadatos a cada solicitud de API para un determinado objeto, independientemente de si estaba paginado o no. También quería simplemente pasar un objeto dict que definí manualmente.
Repetidor Personalizado Tweaked
class CustomJSONRenderer(renderers.JSONRenderer):
def render(self, data, accepted_media_type=None, renderer_context=None):
response_data = {}
# Name the object list
object_list = ''results''
try:
meta_dict = getattr(renderer_context.get(''view'').get_serializer().Meta, ''meta_dict'')
except:
meta_dict = dict()
try:
data.get(''paginated_results'')
response_data[''meta''] = data[''meta'']
response_data[object_list] = data[''results'']
except:
response_data[object_list] = data
response_data[''meta''] = dict()
# Add custom meta data
response_data[''meta''].update(meta_dict)
# Call super to render the response
response = super(CustomJSONRenderer, self).render(response_data, accepted_media_type, renderer_context)
return response
Parent Serializer y ejemplo de vista
class MovieListSerializer(serializers.ModelSerializer):
class Meta:
model = Movie
meta_dict = dict()
meta_dict[''foo''] = ''bar''
class MovieViewSet(generics.ListAPIView):
queryset = Movie.objects.exclude(image__exact = "")
serializer_class = MovieListSerializer
permission_classes = (IsAdminOrReadOnly,)
renderer_classes = (CustomJSONRenderer,)
pagination_serializer_class = CustomPaginationSerializer
paginate_by = 10