Decoratore di verbi http per Django?
-
06-07-2019 - |
Domanda
In ASP.NET MVC, è possibile utilizzare l'attributo AcceptVerbs per correlare una funzione di visualizzazione con un verbo:
public ActionResult Create()
{
// do get stuff
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
// do post stuff
}
Il libro Django suggerisce qualcosa del genere:
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/
Mi sembra un po 'brutto - c'è un decoratore che può associare un verbo HTTP con una vista, stile ASP.NET MVC, o un altro modo accettato per farlo?
, views.method_splitter, {'GET': views.some_page_get,
'POST': views.some_page_post}),
# ...
)
Mi sembra un po 'brutto - c'è un decoratore che può associare un verbo HTTP con una vista, stile ASP.NET MVC, o un altro modo accettato per farlo?
Soluzione
Esistono decoratori integrati standard che richiedono un particolare metodo HTTP o un elenco di metodi consentiti.
Vedi il codice: http: // code. djangoproject.com/browser/django/trunk/django/views/decorators/http.py.
Altri suggerimenti
Risposta aggiornata nel 2016: Modern Django ha tutto il necessario integrato e disponibile tramite viste basate sulla classe . Nella forma più grezza, l'approccio canonico consiste nella sottoclasse di django.views.generic.View
e nell'implementazione di metodi di classe che prendono il nome dai verbi HTTP:
class MyView(View):
def get(self, request, *args, **kwargs):
# ...
def post(self, request, *args, **kwargs):
# ...
Internamente, funziona in un modo molto simile al mio codice antico di seguito (che è stato scritto prima che Django avesse una visione basata sulla classe). Esiste un metodo View.dispatch
che cerca sostanzialmente come chiamare o restituisce 405 se non trova nulla: getattr (self, request.method.lower (), self. http_method_not_allowed)
.
Naturalmente, se si esegue l'elaborazione di moduli, il rendering di modelli o robe CRUD comuni, assicurarsi di controllare le sottoclassi Visualizza
disponibili.
Risposta legacy dal 2009 in poi. Il codice funziona ancora nel 2016, ma non è una soluzione DRY, quindi non utilizzarlo. Nel 2011 Django ha ottenuto viste basate sulla classe e oggi sono il modo standard in cui le cose dovrebbero essere fatte. Lo tengo qui solo per scopi storici. Segue il vecchio testo di risposta:
In una vista particolare in cui ho bisogno di avere un codice separato per diversi metodi HTTP (questa è la mia piccola implementazione WebDAV), sto facendo qualcosa del genere:
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()),
Aggiunto / modificato: Beh, ho pensato un po 'e ho implementato l'approccio del decoratore. Non è così male come inizialmente pensavo.
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'),
Questo post è comunque un wiki della community, quindi sentiti libero di migliorare se ti piace l'idea! E la cronologia delle revisioni contiene anche alcuni approcci un po 'diversi che ho provato prima di scrivere questo ...
Puoi utilizzare Visualizza decoratori
Dai documenti:
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