-
Notifications
You must be signed in to change notification settings - Fork 0
/
djhacker.py
84 lines (62 loc) · 2.62 KB
/
djhacker.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
import re
import types
class Registry(dict):
def register(self, field_class, callback):
self[field_class] = callback
def get(self, field_or_class, *args):
if field_or_class in self:
return super().get(field_or_class, *args)
return super().get(type(field_or_class), *args)
registry = Registry()
def register(field_class):
def _register(callback):
return registry.register(field_class, callback)
return _register
def formfield(model_field, form_class=None, /, **kwargs):
# Syntactic sugar of making form_class an ordered argument
if form_class and 'form_class' not in kwargs:
kwargs['form_class'] = form_class
# In case of re-registration: first un-patch ModelField.formfield()
current = getattr(model_field.field, 'djhacker', None)
if current:
model_field.field.formfield = model_field.field.djhacker['django']
# Call registered callback if any to get more default kwargs
if not form_class:
cb = registry.get(model_field.field)
if cb:
kwargs = {**cb(model_field, **kwargs), **kwargs}
# This function will be set onto .formfield()
def _formfield(self, *args, **kw):
# Add passed kwargs on top of registered kwargs
kwargs = {**self.djhacker['kwargs'], **kw}
# Call django's original formfield method with those kwargs
return self.djhacker['django'](*args, **kwargs)
# Save the original Django formfield() method and store kwargs on field
model_field.field.djhacker = dict(
django=model_field.field.formfield,
kwargs=kwargs,
)
# Patch Django's formfield() method with _formfield
model_field.field.formfield = types.MethodType(
_formfield, model_field.field
)
# That one was nice but we can't use it if we don't want to depend on the regex
# module which seems to have build problems from time to time
# ESM_RE = r'^(?P<path>[^[]+)(\[(?P<key>[^=]+)=(?P<value>[^]]+)\])*$'
ATTRIBUTES = r'\[(?P<key>[^=]+)=(?P<value>[^]]+)\]'
def media_script_attributes():
from django.forms.widgets import Media
from django.utils.html import format_html
def _render_js(self):
result = []
for spec in self._js:
out = '<script src="{}"'
args = [self.absolute_path(spec.partition('[')[0])]
for key, value in re.findall(ATTRIBUTES, spec):
out += ' ' + key + '="{}"'
args.append(value)
out += '></script>'
result.append(format_html(out, *args))
return result
Media.django_render_js = Media.render_js
Media.render_js = _render_js