Estrutura REST do Django: serializador não modelo

158

Sou iniciante no framework REST do Django e preciso de seus conselhos. Estou desenvolvendo um serviço da web. O serviço deve fornecer interface REST para outros serviços. A interface REST, que eu preciso implementar, não está funcionando diretamente com meus modelos (refiro-me às operações get, put, post, delete). Em vez disso, fornece outros serviços com alguns resultados de cálculo. Em uma solicitação, meu serviço faz alguns cálculos e apenas retorna os resultados (não armazena os resultados em seu próprio banco de dados).

Abaixo está o meu entendimento de como essa interface REST pode ser implementada. Corrija-me se eu estiver errada.

  1. Crie uma classe que faça os cálculos. Nomeie-o 'CalcClass'. CalcClass usa os modelos em seu trabalho.
    • Os parâmetros necessários para os cálculos são transmitidos ao construtor.
    • Implemente a operação de calc. Retorna resultados como 'ResultClass'.
  2. Crie ResultClass.
    • Derivado do objeto.
    • Apenas possui atributos que contêm os resultados do cálculo.
    • Uma parte dos resultados do cálculo é representada como tupla de tuplas. Pelo que entendi, seria melhor uma serialização adicional implementar uma classe separada para esses resultados e adicionar uma lista desses objetos ao ResultClass.
  3. Crie o serializador para ResultClass.
    • Derivar de serializadores.Serializer.
    • Os resultados do calc são somente leitura, portanto, use principalmente a classe Field para campos, em vez de classes especializadas, como IntegerField.
    • Eu não deveria implementar o método save () nem no ResultClass nem no Serializer, porque não vou armazenar os resultados (só quero devolvê-los quando solicitado).
    • Implique serializador para resultados aninhados (lembre-se da tupla das tuplas mencionadas acima).
  4. Crie View para retornar os resultados do cálculo.
    • Derive do APIView.
    • Precisa apenas de get ().
    • Em get (), crie CalcClass com os parâmetros recuperados da solicitação, chame calc (), obtenha ResultClass, crie Serializer e passe o ResultClass para ele, retorne Response (serializer.data).
  5. URLs
    • Não há raiz API no meu caso. Eu deveria apenas ter URLs para obter vários resultados de cálculo (cálculo com parâmetros diferentes).
    • Adicione chamadas format_suffix_patterns para navegação na API.

Perdi alguma coisa? A abordagem é correta em geral?

Zakhar
fonte
Essa abordagem está correta e, para mim, na verdade parece mais elegante que a resposta aceita (dados de resultados encapsulados em um tipo de resultado reutilizável). Mas, no final das contas, isso é principalmente uma questão de preferência pessoal e as duas abordagens fazem o trabalho.
Zepp.lee #

Respostas:

157

O Django-rest-framework funciona bem mesmo sem vinculá-lo a um modelo. Sua abordagem parece boa, mas acredito que você pode cortar algumas das etapas para que tudo funcione.

Por exemplo, a estrutura restante vem com alguns renderizadores internos. Fora da caixa, ele pode retornar JSON e XML para o consumidor da API. Você também pode ativar o YAML instalando o módulo python necessário. O Django-rest-framework produzirá qualquer objeto básico como dict, list e tuple sem nenhum trabalho extra de sua parte.

Então, basicamente, você só precisa criar a função ou classe que recebe argumentos, faz todos os cálculos necessários e retorna seus resultados em uma tupla para a visualização da API REST. Se JSON e / ou XML atenderem às suas necessidades, o django-rest-framework cuidará da serialização para você.

Você pode pular as etapas 2 e 3 nesse caso e usar apenas uma classe para cálculos e outra para apresentação ao consumidor da API.

Aqui estão alguns trechos que podem ajudá-lo:

Observe que eu não testei isso. É apenas um exemplo, mas deve funcionar :)

O CalcClass:

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

A visualização 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

Seus 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'),
)

Esse código deve gerar uma lista de listas quando você acessar http://example.com/api/v1.0/resource/?format=json . Se você estiver usando um sufixo, poderá substituir ?format=jsonpor .json. Você também pode especificar a codificação que deseja recuperar adicionando "Content-type"ou "Accept"aos cabeçalhos.

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

Espero que isso ajude você.

Gabriel Samfira
fonte
2
Oi Gabriel! Obrigado pela sua resposta! Eu já implementei o que preciso de acordo com meu plano. Funciona bem! Eu usei o serializador para melhor saída json.
Zakhar
3
Eu tentei seguir esta sugestão, mas obtive: "Não é possível aplicar o DjangoModelPermissions em uma exibição que não possui .modelou .querysetpropriedade.". Eu tentei o exemplo exato fornecido. Poderia ser algo com a versão recente do django-rest-framework?
Orlando
Este exemplo foi escrito há algum tempo. Desde então, não tive a chance de trabalhar com o Django novamente. mas você pode encontrar algo útil aqui: django-rest-framework.org/api-guide/routers
Gabriel Samfira
1
Este exemplo é exatamente o que eu precisava para a minha necessidade é um serviço que está executando algumas operações sem um serializador não modelo!
Khalil TABBAL 03/07/2015
@Orlando: Dê uma olhada aqui como implementar uma permissão específica, lógica para uma visão não-modelo com Djang-restframework 3: stackoverflow.com/a/34040070/640916
djangonaut
-1

No urls.py, a função login_required requer

from django.contrib.auth.decorators import login_required
ymorvan
fonte
se isso é apenas um comentário em vez de uma resposta, considere usar a add a commentsessão
lucascavalcante