@@ -8,11 +8,11 @@ images/files, nesting).
8
8
9
9
- payload parsing (according to the ` Content-Type ` HTTP header)
10
10
- data validation and normalisation (using [ Django validators] ( https://docs.djangoproject.com/en/4.1/ref/validators/ )
11
- or custom ` clean_ ` method)
11
+ or custom ` clean_ ` method)
12
12
- BASE64 file/image upload
13
13
- construction of the basic validation response
14
14
- filling objects attributes (if possible, see exceptions) using ` setattr ` function (super handy for Django database
15
- models)
15
+ models)
16
16
17
17
## Construction
18
18
@@ -24,6 +24,7 @@ any extra argument into `Form.create_from_request(request, param1=request.GET.ge
24
24
``` python
25
25
from tests.testapp.forms import AlbumForm
26
26
27
+
27
28
def my_view (request ):
28
29
form = AlbumForm.create_from_request(request = request, param = request.GET .get(' param' ))
29
30
```
@@ -80,13 +81,13 @@ class BandForm(Form):
80
81
This process is much more simple than in classic Django form. It consists of:
81
82
82
83
1 . Iterating over form attributes:
83
- - calling ` Field.clean(value) ` method
84
- - calling ` Form.clean_<field_name> ` method
85
- - calling ` Form.add_error((field_name, ), error) ` in case of failures in clean methods
86
- - if field is marked as dirty, normalized attribute is saved to ` Form.clean_data ` property
84
+ - calling ` Field.clean(value) ` method
85
+ - calling ` Form.clean_<field_name> ` method
86
+ - calling ` Form.add_error((field_name, ), error) ` in case of failures in clean methods
87
+ - if field is marked as dirty, normalized attribute is saved to ` Form.clean_data ` property
87
88
2 . Calling ` Form.clean ` method which returns final normalized values which will be presented in ` Form.clean_data `
88
- (feel free to override it, by default does nothing, useful for conditional validation, you can still add errors
89
- using ` Form.add_error() ` ). ` Form.clean ` is only called when there are no errors from previous section.
89
+ (feel free to override it, by default does nothing, useful for conditional validation, you can still add errors
90
+ using ` Form.add_error() ` ). ` Form.clean ` is only called when there are no errors from previous section.
90
91
91
92
Normalized data are available in ` Form.clean_data ` property (keys suppose to correspond with values from ` Form.dirty ` ).
92
93
Extra optional arguments are available in ` Form.extras ` property (keys suppose to correspond with values
@@ -106,13 +107,14 @@ from django.forms import fields
106
107
from django.core.exceptions import ValidationError
107
108
from django_api_forms import Form
108
109
110
+
109
111
class BookForm (Form ):
110
112
title = fields.CharField(max_length = 100 )
111
113
year = fields.IntegerField()
112
114
113
115
def clean_title (self ):
114
116
if self .cleaned_data[' title' ] == " The Hitchhiker's Guide to the Galaxy" :
115
- self .add_error((' title' , ), ValidationError(" Too cool!" , code = ' too-cool' ))
117
+ self .add_error((' title' ,), ValidationError(" Too cool!" , code = ' too-cool' ))
116
118
117
119
if ' param' not in self .extras:
118
120
raise ValidationError(" You can use extra optional arguments in form validation!" )
@@ -125,7 +127,7 @@ class BookForm(Form):
125
127
126
128
if ' param' not in self .extras:
127
129
self .add_error(
128
- (' param' , ),
130
+ (' param' ,),
129
131
ValidationError(" You can use extra optional arguments in form validation!" , code = ' param-where' )
130
132
)
131
133
# The last chance to do some touchy touchy with the self.clean_data
@@ -150,6 +152,7 @@ can use it like this:
150
152
from tests.testapp.forms import AlbumForm
151
153
from tests.testapp.models import Album
152
154
155
+
153
156
def my_view (request ):
154
157
form = AlbumForm.create_from_request(request)
155
158
@@ -173,7 +176,7 @@ DJANGO_API_FORMS_POPULATION_STRATEGIES = {
173
176
' django_api_forms.fields.FormFieldList' : ' django_api_forms.population_strategies.IgnoreStrategy' ,
174
177
' django_api_forms.fields.FileField' : ' django_api_forms.population_strategies.IgnoreStrategy' ,
175
178
' django_api_forms.fields.ImageField' : ' django_api_forms.population_strategies.IgnoreStrategy' ,
176
- ' django_api_forms.fields.FormField' : ' django_api_forms.population_strategies.IgnoreStrategy ' ,
179
+ ' django_api_forms.fields.FormField' : ' django_api_forms.population_strategies.FormFieldStrategy ' ,
177
180
' django.forms.models.ModelMultipleChoiceField' : ' django_api_forms.population_strategies.IgnoreStrategy' ,
178
181
' django.forms.models.ModelChoiceField' : ' django_api_forms.population_strategies.ModelChoiceFieldStrategy'
179
182
}
@@ -205,18 +208,44 @@ from django_api_forms import Form
205
208
206
209
from tests.testapp.models import Artist
207
210
211
+
208
212
class MyFormNoPostfix (Form ):
209
213
artist = ModelChoiceField(queryset = Artist.objects.all())
210
214
215
+
211
216
class MyFormFieldName (Form ):
212
217
artist_name = ModelChoiceField(
213
218
queryset = Artist.objects.all(), to_field_name = ' name'
214
219
)
215
220
221
+
216
222
class MyFormWithId (Form ):
217
223
artist_id = ModelChoiceField(queryset = Artist.objects.all())
218
224
```
219
225
226
+ #### FormFieldStrategy
227
+
228
+ If the ` model ` argument is omitted, the ` FormFieldStrategy ` will behave same as the ` IgnoreStrategy `
229
+ If a ` model ` argument is provided when declaring a ` FormField ` , the data from the nested JSON object is used to
230
+ populate an instance of the specified Django model.
231
+
232
+ ``` python
233
+ from django.forms import fields
234
+
235
+ from django_api_forms import FieldList, FormField, Form
236
+ from tests.testapp.models import Artist
237
+
238
+
239
+ class ArtistForm (Form ):
240
+ name = fields.CharField(required = True , max_length = 100 )
241
+ genres = FieldList(field = fields.CharField(max_length = 30 ))
242
+ members = fields.IntegerField()
243
+
244
+
245
+ class AlbumForm (Form ):
246
+ artist = FormField(form = ArtistForm, model = Artist)
247
+ ```
248
+
220
249
### Customization
221
250
222
251
#### Creating custom strategy
@@ -236,8 +265,9 @@ class ExampleStrategy(BaseStrategy):
236
265
237
266
#### Override strategy
238
267
239
- You can override settings population strategies by creating your own population strategy in specific local ` From ` class using
240
- ` Meta ` class with optional attributes ` field_type_strategy = {} ` or ` field_strategy = {} ` :
268
+ You can override settings population strategies by creating your own population strategy in specific local ` From ` class
269
+ using ` Meta ` class with optional attributes ` field_type_strategy = {} ` or ` field_strategy = {} ` :
270
+
241
271
- ` field_type_strategy ` : Dictionary for overriding populate strategy on ` Form ` type attributes
242
272
- ` field_strategy ` : Dictionary for overriding populate strategies on ` Form ` attributes
243
273
@@ -276,6 +306,7 @@ from django_api_forms import Form, FormField, EnumField, DictionaryField
276
306
from tests.testapp.models import Album, Artist
277
307
from tests.testapp.forms import ArtistForm
278
308
309
+
279
310
class AlbumForm (Form ):
280
311
title = fields.CharField(max_length = 100 )
281
312
year = fields.IntegerField()
0 commit comments