Skip to content

Commit 72fa802

Browse files
committed
more
1 parent 44d98de commit 72fa802

File tree

6 files changed

+278
-33
lines changed

6 files changed

+278
-33
lines changed

bukdjango_multiform/views.py

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
11
from django import forms
22
from django.http import HttpResponseBadRequest
3+
from django.utils.decorators import method_decorator
34
from django.utils.functional import cached_property
45
from django.views.generic import TemplateView
56

67

78
class NewMultiForm(type):
89

9-
def __init__(cls, name, bases, clsdict):
10-
super().__init__(name, bases, clsdict)
11-
12-
if clsdict.get('multiforms'):
13-
clsdict.setdefault('multiform_field_name', 'formtype')
14-
field_name = clsdict.get('multiform_field_name')
15-
for k, v in clsdict['multiforms'].items():
16-
clsdict['multiforms'][k]['class'] = type(
10+
def __new__(mcs, name, bases, attrs):
11+
new_class = super().__new__(mcs, name, bases, attrs)
12+
13+
multiforms = {}
14+
for base in reversed(new_class.__mro__):
15+
if hasattr(base, 'multiforms'):
16+
multiforms.update(base.multiforms)
17+
for k, v in base.multiforms.items():
18+
if v is None and k in multiforms:
19+
multiforms.pop(k)
20+
21+
if multiforms:
22+
field_name = attrs.get('multiform_field_name', 'formtype')
23+
for k, v in multiforms.items():
24+
multiforms[k]['class'] = type(
1725
v['class'].__name__,
1826
(v['class'],),
1927
{field_name: forms.CharField(
@@ -22,7 +30,13 @@ def __init__(cls, name, bases, clsdict):
2230
)}
2331
)
2432

33+
new_class.multiforms = multiforms
34+
35+
return new_class
2536

37+
38+
# todo before post we should decorate
39+
# todo for ex. login required or other checks per form
2640
class MultiFormMixin(metaclass=NewMultiForm):
2741

2842
multiforms = {}
@@ -61,6 +75,18 @@ def form_params(self):
6175
self.form_name
6276
)
6377

78+
@cached_property
79+
def form_checks(self):
80+
return self.multiforms.get(
81+
self.form_name
82+
).get('checks', None)
83+
84+
@cached_property
85+
def form_save(self):
86+
return self.multiforms.get(
87+
self.form_name
88+
).get('save', False)
89+
6490
def get_form_kwargs(self, name, params, **kwargs):
6591
if attrs := params.get('attrs'):
6692
for attr in attrs:
@@ -72,25 +98,18 @@ def get_form_kwargs(self, name, params, **kwargs):
7298
kwargs.update(func(**kwargs))
7399
return kwargs
74100

75-
76-
class MultiFormTemplateView(MultiFormMixin, TemplateView):
77-
78-
def get_context_data(self, **kwargs):
79-
ctx = super().get_context_data(**kwargs)
80-
for k, v in self.multiforms.items():
81-
if not kwargs.get(k):
82-
ctx[k] = v['class'](
83-
**self.get_form_kwargs(
84-
name=k, params=v,
85-
)
86-
)
87-
return ctx
88-
89101
def post(self, request, *args, **kwargs):
90102

91103
if not self.form_params:
92104
return HttpResponseBadRequest()
93105

106+
if self.form_checks:
107+
for check in self.form_checks:
108+
if response := check(
109+
request, *args, **kwargs,
110+
):
111+
return response
112+
94113
form = self.form_class(
95114
**self.get_form_kwargs(
96115
name=self.form_name,
@@ -105,19 +124,35 @@ def post(self, request, *args, **kwargs):
105124

106125
return self.form_invalid(form)
107126

108-
def post_response(self, form):
109-
return self.render_to_response(
110-
context=self.get_context_data(**{
111-
self.form_name: form,
112-
})
113-
)
114-
115127
def form_valid(self, form):
116128
if handler := self.valid_handle:
117129
return handler(form=form)
130+
if self.form_save:
131+
form.save()
118132
return self.post_response(form)
119133

120134
def form_invalid(self, form):
121135
if handler := self.invalid_handle:
122136
return handler(form=form)
123137
return self.post_response(form)
138+
139+
140+
class MultiFormTemplateView(MultiFormMixin, TemplateView):
141+
142+
def get_context_data(self, **kwargs):
143+
ctx = super().get_context_data(**kwargs)
144+
for k, v in self.multiforms.items():
145+
if not kwargs.get(k):
146+
ctx[k] = v['class'](
147+
**self.get_form_kwargs(
148+
name=k, params=v,
149+
)
150+
)
151+
return ctx
152+
153+
def post_response(self, form):
154+
return self.render_to_response(
155+
context=self.get_context_data(**{
156+
self.form_name: form,
157+
})
158+
)

tests/forms.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
from django import forms
22

33

4+
class FormSavedException(Exception):
5+
pass
6+
7+
48
class Form1(forms.Form):
59
field1 = forms.CharField(widget=forms.TextInput())
610
field2 = forms.CharField(widget=forms.TextInput())
@@ -16,8 +20,15 @@ def clean_field1(self):
1620
'Error! Wrong Value!'
1721
)
1822

23+
def save(self):
24+
raise FormSavedException()
25+
1926

2027
class Form2(forms.Form):
2128
field1 = forms.CharField(widget=forms.TextInput(), required=True)
2229
field2 = forms.CharField(widget=forms.TextInput(), required=True)
2330

31+
def save(self):
32+
raise FormSavedException()
33+
34+

tests/templates/index.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
{% csrf_token %}
1818
<input type="submit">
1919
</form>
20+
form3_ctx<br>
21+
<form method="post">
22+
{{ form3_ctx }}
23+
{% csrf_token %}
24+
<input type="submit">
25+
</form>
2026

2127
</body>
2228
</html>

tests/tests.py

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,119 @@
1-
from django.test import TestCase, Client
1+
from django.test import TestCase
2+
from .forms import FormSavedException
3+
from .views import MyMultiFormTemplateView4, MyMultiFormTemplateView3
24

35

46
class AppTestCase(TestCase):
57

8+
def test_save(self):
9+
with self.assertRaises(FormSavedException) as err:
10+
r = self.client.post(
11+
'/decoratorview2/6',
12+
data={
13+
'field1': '1',
14+
'field2': 'a',
15+
'formtype': 'form1_ctx'
16+
}
17+
)
18+
19+
def test_checks(self):
20+
r = self.client.post(
21+
'/decoratorview/1',
22+
data={
23+
'field1': '1',
24+
'field2': 'a',
25+
'formtype': 'form1_ctx'
26+
}
27+
)
28+
self.assertEqual(
29+
r.status_code, 403
30+
)
31+
self.assertEqual(
32+
b'loginplease', r.content,
33+
)
34+
35+
def test_checks2(self):
36+
r = self.client.post(
37+
'/decoratorview2/5',
38+
data={
39+
'field1': '1',
40+
'field2': 'a',
41+
'formtype': 'form1_ctx'
42+
}
43+
)
44+
self.assertEqual(
45+
r.status_code, 408
46+
)
47+
self.assertNotEqual(
48+
b'loginplease', r.content,
49+
)
50+
51+
def test_multiclass_post(self):
52+
r = self.client.post(
53+
'/view4/5',
54+
data={
55+
'field1': '1',
56+
'field2': 'a',
57+
'zxc': 'form4_ctx'
58+
}
59+
)
60+
self.assertEqual(
61+
r.status_code, 200
62+
)
63+
64+
r = self.client.post(
65+
'/view4/5',
66+
data={
67+
'field1': '1',
68+
'field2': 'a',
69+
'zxc': 'form2_ctx'
70+
}
71+
)
72+
self.assertEqual(
73+
r.status_code, 400
74+
)
75+
76+
r = self.client.post(
77+
'/view4/5',
78+
data={
79+
'field1': '1',
80+
'field2': 'a',
81+
'zxc': 'form1_ctx'
82+
}
83+
)
84+
self.assertEqual(
85+
r.status_code, 200
86+
)
87+
88+
def test_multiclass(self):
89+
90+
view = MyMultiFormTemplateView3()
91+
desired = {
92+
'form3_ctx': {
93+
},
94+
'form1_ctx': {
95+
},
96+
'form2_ctx': {
97+
},
98+
}
99+
self.assertEqual(
100+
view.multiforms.keys(),
101+
desired.keys(),
102+
)
103+
104+
view = MyMultiFormTemplateView4()
105+
print(view.multiforms)
106+
desired = {
107+
'form1_ctx': {
108+
},
109+
'form4_ctx': {
110+
},
111+
}
112+
self.assertEqual(
113+
view.multiforms.keys(),
114+
desired.keys(),
115+
)
116+
6117
def test_render_1(self):
7118
r = self.client.get('/')
8119
self.assertEqual(

tests/urls.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
from django.urls import path
22

3-
from .views import MyMultiFormTemplateView1, MyMultiFormTemplateView2
3+
from .views import DecoratorFormTemplateView3, DecoratorFormTemplateView2, DecoratorFormTemplateView, MyMultiFormTemplateView1, MyMultiFormTemplateView2, MyMultiFormTemplateView4
44

55

66
urlpatterns = [
77
path('<int:some_kwarg>', MyMultiFormTemplateView1.as_view()),
88
path('test', MyMultiFormTemplateView2.as_view()),
9+
path('view4/<int:some_kwarg>', MyMultiFormTemplateView4.as_view()),
10+
path('decoratorview/<int:some_kwarg>', DecoratorFormTemplateView.as_view()),
11+
path('decoratorview2/<int:some_kwarg>', DecoratorFormTemplateView3.as_view())
912
]

0 commit comments

Comments
 (0)