Django REST framework: serializador no modelo

158

Soy principiante en Django REST framework y necesito tu consejo. Estoy desarrollando un servicio web. El servicio tiene que proporcionar una interfaz REST a otros servicios. La interfaz REST, que necesito implementar, no funciona con mis modelos directamente (me refiero a las operaciones get, put, post, delete). En cambio, proporciona otros servicios con algunos resultados de cálculo. En una solicitud, mi servicio hace algunos cálculos y solo devuelve los resultados (no almacena los resultados en su propia base de datos).

A continuación, entiendo cómo se podría implementar esa interfaz REST. Corrígeme si estoy equivocado.

  1. Crear clase que hace los cálculos. Nómbrelo 'CalcClass'. CalcClass utiliza los modelos en su trabajo.
    • Los parámetros necesarios para los cálculos se pasan al constructor.
    • Implementar la operación calc. Devuelve resultados como 'ResultClass'.
  2. Crear ResultClass.
    • Derivado del objeto.
    • Solo tiene atributos que contienen los resultados de cálculo.
    • Una parte de los resultados del cálculo se representa como una tupla de tuplas. Según tengo entendido, sería mejor para una mayor serialización implementar una clase separada para esos resultados y agregar una lista de dichos objetos a ResultClass.
  3. Crear serializador para ResultClass.
    • Derivar de serializadores. Serializador.
    • Los resultados de cálculo son de solo lectura, por lo tanto, use principalmente la clase Field para campos, en lugar de clases especializadas, como IntegerField.
    • No debería implicar el método save () ni en ResultClass ni en Serializer, porque no voy a almacenar los resultados (solo quiero devolverlos a pedido).
    • Impl serializador para resultados anidados (recuerde la tupla de tuplas mencionadas anteriormente).
  4. Crear vista para devolver los resultados del cálculo.
    • Derivar de APIView.
    • Solo necesita obtener ().
    • En get () cree CalcClass con los parámetros recuperados de la solicitud, llame a su calc (), obtenga ResultClass, cree Serializer y pásele el ResultClass, devuelva Response (serializer.data).
  5. URLs
    • No hay raíz api en mi caso. Debería tener URL para obtener varios resultados de cálculo (cálculo con parámetros de diferencia).
    • Agregue el formato format_suffix_patterns para la exploración de la API.

¿Me he perdido algo? ¿El enfoque es correcto en general?

Zakhar
fuente
Este enfoque es correcto y para mí en realidad se ve más elegante que la respuesta aceptada (datos de resultados encapsulados en un tipo de resultado reutilizable). Pero al final del día, esto es principalmente una cuestión de preferencia personal y ambos enfoques hacen el trabajo.
zepp.lee

Respuestas:

157

Django-rest-framework funciona bien incluso sin vincularlo a un modelo. Su enfoque suena bien, pero creo que puede recortar algunos de los pasos para que todo funcione.

Por ejemplo, rest framework viene con algunos renderizadores integrados. Fuera de la caja, puede devolver JSON y XML al consumidor de API. También puede habilitar YAML simplemente instalando el módulo python requerido. Django-rest-framework generará cualquier objeto básico como dict, list y tuple sin ningún trabajo adicional de su parte.

Básicamente, solo tiene que crear la función o clase que toma argumentos, realiza todos los cálculos necesarios y devuelve sus resultados en una tupla a la vista de la API REST. Si JSON y / o XML se ajustan a sus necesidades, django-rest-framework se encargará de la serialización por usted.

Puede omitir los pasos 2 y 3 en este caso, y solo usar una clase para los cálculos y otra para la presentación al consumidor de API.

Aquí hay algunos fragmentos que pueden ayudarte:

Tenga en cuenta que no he probado esto. Solo significa un ejemplo, pero debería funcionar :)

La clase Calc:

class CalcClass(object):

    def __init__(self, *args, **kw):
        # Initialize any variables you need from the input you get
        pass

    def do_work(self):
        # Do some calculations here
        # returns a tuple ((1,2,3, ), (4,5,6,))
        result = ((1,2,3, ), (4,5,6,)) # final result
        return result

La vista REST:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

from MyProject.MyApp import CalcClass


class MyRESTView(APIView):

    def get(self, request, *args, **kw):
        # Process any get params that you may need
        # If you don't need to process get params,
        # you can skip this part
        get_arg1 = request.GET.get('arg1', None)
        get_arg2 = request.GET.get('arg2', None)

        # Any URL parameters get passed in **kw
        myClass = CalcClass(get_arg1, get_arg2, *args, **kw)
        result = myClass.do_work()
        response = Response(result, status=status.HTTP_200_OK)
        return response

Tu urls.py:

from MyProject.MyApp.views import MyRESTView
from django.conf.urls.defaults import *

urlpatterns = patterns('',
    # this URL passes resource_id in **kw to MyRESTView
    url(r'^api/v1.0/resource/(?P<resource_id>\d+)[/]?$', login_required(MyRESTView.as_view()), name='my_rest_view'),
    url(r'^api/v1.0/resource[/]?$', login_required(MyRESTView.as_view()), name='my_rest_view'),
)

Este código debería generar una lista de listas cuando accede a http://example.com/api/v1.0/resource/?format=json . Si usa un sufijo, puede sustituirlo ?format=jsonpor .json. También puede especificar la codificación que desea recuperar agregando "Content-type"o "Accept"a los encabezados.

[
  [
    1, 
    2, 
    3
  ], 
  [
    4, 
    5, 
    6
  ]
]

Espero que esto te ayude.

Gabriel Samfira
fuente
2
Hola gabriel ¡Gracias por su respuesta! Ya implementé lo que necesito según mi plan. ¡Funciona bien! Usé el serializador para una mejor salida json.
Zakhar
3
He intentado seguir esta sugerencia pero aparece: "No se puede aplicar DjangoModelPermissions en una vista que no tiene .modelo .querysetpropiedad". He intentado el ejemplo exacto proporcionado. ¿Podría ser algo con la versión reciente de django-rest-framework?
Orlando
Este ejemplo ha sido escrito hace algún tiempo. Desde entonces no he tenido la oportunidad de trabajar con Django nuevamente. pero puede encontrar algo útil aquí: django-rest-framework.org/api-guide/routers
Gabriel Samfira
1
¡Este ejemplo es exactamente lo que necesitaba para mi necesidad es un servicio que está haciendo algunas operaciones sin un serializador no modelo!
Khalil TABBAL
@Orlando: Vea aquí cómo implementar la lógica de permisos específica para una vista no modelo con djang-restframework 3: stackoverflow.com/a/34040070/640916
djangonaut
-1

En urls.py, la función login_required requiere

from django.contrib.auth.decorators import login_required
ymorvan
fuente
si eso es solo un comentario en lugar de una respuesta, considere usar la add a commentsesión
lucascavalcante