-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathdecorators.py
85 lines (59 loc) · 2.48 KB
/
decorators.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
from typing import Callable, Dict
from django.http import HttpResponse
from .utils import Ajax
def ajax_dispatch(views_map: Dict[str, Callable]) -> Callable:
"""Decorator. Allows ajax request dispatch based
on source html element identifiers.
Useful in cases when various ajax calls have a single entry point view.
.. code-block::
// JS. Define an element with `id`.
<button id="replaceit" hx-get="/">Push me</button>
// Python. Define a handling view and an entry point view decorated.
def do_replace(request):
return HttpResponse('Thank you')
@ajax_dispatch({
'replaceit': do_replace, # Map element id to a handler
'prefixed-some-*': do_replace, # Map several id with the same prefix
})
def index(request):
return HttpResponse('not ajax')
:param views_map: Map html elements IDs to handling functions.
To match several IDs use start (*)
"""
wildcards = {}
ids = {}
for key, handler in views_map.items():
prefix, sep, _ = key.partition('*')
if sep == '*':
wildcards[prefix] = handler
else:
ids[key] = handler
def ajax_view_(func: Callable) -> Callable:
def view_wrapper(*fargs, **fkwargs) -> HttpResponse:
request = fargs[0]
if not hasattr(request, 'POST'):
# Possibly a class-based view where 0-attr is `self`.
request = fargs[1]
if hasattr(request, 'ajax'):
# Attribute is already set by middleware.
ajax: Ajax = request.ajax
else:
# Initialize on fly.
ajax = Ajax(request)
request.ajax = ajax
if ajax:
source_id = ajax.source.id
handling_view = ids.get(source_id)
if not handling_view:
# Long way to process wildcards.
for id_prefix, handling in wildcards.items():
if source_id.startswith(id_prefix):
handling_view = handling
break
if handling_view:
response = handling_view(*fargs, **fkwargs)
# Try to unwrap an AjaxResponse if any.
return getattr(response, 'wrapped_response', response)
return func(*fargs, **fkwargs)
return view_wrapper
return ajax_view_