1
1
# noinspection PyUnresolvedReferences
2
2
import inspect
3
+ import re
3
4
4
5
from django .core .exceptions import FieldDoesNotExist
5
6
from django .db .models import TextField
6
- from django .http import HttpResponseNotFound
7
+ from django .http import HttpResponseNotFound , Http404
7
8
from django .utils .translation import gettext
8
9
from rest_framework import renderers
9
10
from rest_framework .decorators import detail_route , list_route
@@ -60,6 +61,12 @@ class AngularFormMixin(object):
60
61
form_titles = {}
61
62
form_defaults_map = {}
62
63
64
+ """
65
+ A map of linked forms, i.e. forms defined on other viewsets linked by foreign key or m2m. See @linked_forms
66
+ decorator and linked_form(...) call for details.
67
+ """
68
+ linked_forms = {}
69
+
63
70
@staticmethod
64
71
def fieldset (title , controls ):
65
72
"""
@@ -104,22 +111,22 @@ def group(*controls):
104
111
# noinspection PyUnusedLocal
105
112
@detail_route (renderer_classes = [renderers .JSONRenderer ], url_path = 'form' )
106
113
def form (self , request , * args , ** kwargs ):
107
- return self ._get_form_metadata (has_instance = True )
114
+ return Response ( self ._get_form_metadata (has_instance = True ) )
108
115
109
116
# noinspection PyUnusedLocal
110
117
@list_route (renderer_classes = [renderers .JSONRenderer ], url_path = 'form' )
111
118
def form_list (self , request , * args , ** kwargs ):
112
- return self ._get_form_metadata (has_instance = False )
119
+ return Response ( self ._get_form_metadata (has_instance = False ) )
113
120
114
121
# noinspection PyUnusedLocal
115
122
@detail_route (renderer_classes = [renderers .JSONRenderer ], url_path = 'form/(?P<form_name>.+)' )
116
123
def form_with_name (self , request , * args , form_name = None , ** kwargs ):
117
- return self ._get_form_metadata (has_instance = True , form_name = form_name or '' )
124
+ return Response ( self ._get_form_metadata (has_instance = True , form_name = form_name or '' ) )
118
125
119
126
# noinspection PyUnusedLocal
120
127
@list_route (renderer_classes = [renderers .JSONRenderer ], url_path = 'form/(?P<form_name>.+)' )
121
128
def form_list_with_name (self , request , * args , form_name = None , ** kwargs ):
122
- return self ._get_form_metadata (has_instance = False , form_name = form_name or '' )
129
+ return Response ( self ._get_form_metadata (has_instance = False , form_name = form_name or '' ) )
123
130
124
131
#
125
132
# the rest of the methods on this class are private ones
@@ -272,12 +279,16 @@ def _get_actions(self, has_instance, serializer):
272
279
def _get_form_metadata (self , has_instance , form_name = '' ):
273
280
274
281
if form_name :
282
+
283
+ if form_name in self .linked_forms :
284
+ return self ._linked_form_metadata (form_name )
285
+
275
286
if not self .form_layouts :
276
- return HttpResponseNotFound ('Form layouts not configured. '
287
+ raise Http404 ('Form layouts not configured. '
277
288
'Please add form_layouts attribute on the viewset class' )
278
289
279
290
if form_name not in self .form_layouts :
280
- return HttpResponseNotFound ('Form with name %s not found' % form_name )
291
+ raise Http404 ('Form with name %s not found' % form_name )
281
292
282
293
ret = {}
283
294
@@ -301,8 +312,21 @@ def _get_form_metadata(self, has_instance, form_name=''):
301
312
ret ['hasInitialData' ] = has_instance
302
313
303
314
# print(json.dumps(ret, indent=4))
315
+ return ret
304
316
305
- return Response (ret )
317
+ def _linked_form_metadata (self , form_name ):
318
+ form_def = self .linked_forms [form_name ]
319
+ viewset = form_def ['viewset' ]()
320
+ viewset .request = self .request
321
+ viewset .format_kwarg = self .format_kwarg
322
+ ret = viewset ._get_form_metadata (False , form_name = form_def ['form_id' ])
323
+
324
+ path = self .request .path
325
+ # must be called from /form/ ...
326
+ path = re .sub (r'/form(/[^/]+)?/?$' , '' , path )
327
+
328
+ ret ['djangoUrl' ] = '%s/%s/' % (path , form_name )
329
+ return ret
306
330
307
331
# @LoggerDecorator.log()
308
332
def _decorate_layout (self , layout , fields_info ):
@@ -340,3 +364,5 @@ def _decorate_layout_item(self, item):
340
364
def camel (snake_str ):
341
365
first , * others = snake_str .split ('_' )
342
366
return '' .join ([first .lower (), * map (str .title , others )])
367
+
368
+
0 commit comments