Http verbo decorador para Django?
-
06-07-2019 - |
Pregunta
En ASP.NET MVC, puede usar el atributo AcceptVerbs para correlacionar una función de vista con un verbo:
public ActionResult Create()
{
// do get stuff
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
// do post stuff
}
El libro de Django sugiere algo como esto:
def method_splitter(request, *args, **kwargs):
get_view = kwargs.pop('GET', None)
post_view = kwargs.pop('POST', None)
if request.method == 'GET' and get_view is not None:
return get_view(request, *args, **kwargs)
elif request.method == 'POST' and post_view is not None:
return post_view(request, *args, **kwargs)
raise Http404
urls.py:
urlpatterns = patterns('',
# ...
(r'^somepage/
Eso me parece un poco feo: ¿hay un decorador que pueda asociar un verbo HTTP con una vista, ASP.NET MVC-style u otra forma aceptada de hacer esto?
, views.method_splitter, {'GET': views.some_page_get,
'POST': views.some_page_post}),
# ...
)
Eso me parece un poco feo: ¿hay un decorador que pueda asociar un verbo HTTP con una vista, ASP.NET MVC-style u otra forma aceptada de hacer esto?
Solución
Hay decoradores integrados estándar que requieren un método HTTP particular o una lista de métodos permitidos.
Vea el código: http: // code. djangoproject.com/browser/django/trunk/django/views/decorators/http.py .
Otros consejos
Respuesta actualizada en 2016: Modern Django tiene todo lo necesario incorporado y disponible a través de vistas basadas en clases . En la forma más cruda, el enfoque canónico es subclasificar django.views.generic.View
e implementar métodos de clase que llevan el nombre de los verbos HTTP:
class MyView(View):
def get(self, request, *args, **kwargs):
# ...
def post(self, request, *args, **kwargs):
# ...
Internamente, esto funciona de una manera muy similar a mi antiguo código a continuación (que fue escrito antes de que Django tuviera vistas basadas en clases). Hay un método View.dispatch
que básicamente busca qué llamar o devolver 405 si no puede encontrar nada: getattr (self, request.method.lower (), self. http_method_not_allowed)
.
Por supuesto, si realiza el procesamiento de formularios, la representación de plantillas o cosas CRUD comunes, asegúrese de revisar las subclases View
disponibles.
Respuesta heredada de 2009 a continuación. El código todavía funciona en 2016, pero no es una solución SECA, así que no lo use. En 2011, Django obtuvo vistas basadas en clases y hoy en día son la forma estándar de cómo deben hacerse las cosas. Lo mantendré aquí únicamente con fines históricos. El texto de respuesta anterior sigue:
En una vista particular donde necesito tener un código separado para diferentes métodos HTTP (esta es mi pequeña implementación de WebDAV), estoy haciendo algo como esto:
class SomeView(object):
def method_get(self, request, ...):
...
def __call__(self, request, *args, **kwargs):
m = getattr(self, 'method_%s' % request.method.lower(), None)
if m is not None:
return m(request, user, *args, **kwargs)
return HttpResponseNotAllowed("405 Method Not Allowed")
# Then url(r'...', SomeView()),
Agregado / editado: Bueno, lo pensé un poco y realmente implementé el enfoque de decorador. No es tan malo como pensé inicialmente.
def method_not_allowed_view(request, *args, **kwargs):
return HttpResponseNotAllowed("405 Method Not Allowed")
def http_method(*methods):
methods = map(lambda m: m.lower(), methods)
def __method_wrapper(f):
this_module = __import__(__name__)
chain = getattr(this_module, f.__name__, method_not_allowed_view)
base_view_func = lambda request, *args, **kwargs: \
f(request, *args, **kwargs) if request.method.lower() in methods \
else chain(request, *args, **kwargs)
setattr(this_module, f.__name__, base_view_func)
return base_view_func
return __method_wrapper
@http_method('get')
def my_view(request):
return HttpResponse("Thank you for GETting.")
@http_method('post', 'put')
def my_view(request):
return HttpResponse("Thank you for POSTing or PUTting.")
# url(r'...', 'app.my_view'),
Esta publicación es una wiki de la comunidad, de todos modos, así que siéntete libre de mejorar si te gusta la idea. Y el historial de revisiones también contiene algunos enfoques un poco diferentes que probé antes de escribir esto ...
Puede usar Ver decoradores
De la documentación:
from django.views.decorators.http import require_http_methods
@require_http_methods(["GET", "POST"])
def my_view(request):
# I can assume now that only GET or POST requests make it this far
# ...
pass