Skip to content

Commit de65602

Browse files
authored
Fixed missing validation errors (#42) πŸ‘¨πŸ½β€πŸ«
* DictionaryField exception handling * Fixed missing validation errors * Added valid nested forms test * Fixed flake8 codestyle * Removed str option from Form.add_error() argument
1 parent 2d1a9dc commit de65602

File tree

10 files changed

+527
-70
lines changed

10 files changed

+527
-70
lines changed

β€ŽCHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## 1.0.0-rc.4 : 06.09.2022
4+
5+
- **Fixed**: Fixed missing validation errors
6+
- **Changed**: `Form.add_error()` now takes only `Tuple` as a `field` argument
7+
38
## 1.0.0-rc.3 : 04.09.2022
49

510
- **Fixed**: Removed validation of non-required fields if they are not present in the request

β€Ždjango_api_forms/exceptions.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,19 @@ class UnsupportedMediaType(ApiFormException):
1515

1616
class DetailValidationError(ValidationError):
1717
def __init__(self, error: ValidationError, path: Tuple):
18-
super().__init__(error.message, error.code, error.params)
18+
if not hasattr(error, 'message') and isinstance(error.error_list, list):
19+
for item in error.error_list:
20+
item.path = path
21+
22+
super().__init__(error)
1923
self._path = path
2024

2125
@property
2226
def path(self) -> Tuple:
2327
return self._path
2428

25-
def prepend(self, key: str):
26-
self._path = (key, ) + self._path
29+
def prepend(self, key: Tuple):
30+
self._path = key + self._path
2731

2832
def to_list(self) -> list:
2933
return list(self.path)

β€Ždjango_api_forms/fields.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def to_python(self, value):
142142
result.append(form.cleaned_data)
143143
else:
144144
for error in form.errors:
145-
error.prepend(position)
145+
error.prepend((position, ))
146146
errors.append(error)
147147

148148
if errors:

β€Ždjango_api_forms/forms.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import copy
2-
from typing import Union, List, Tuple
2+
from typing import List, Tuple
33

44
from django.core.exceptions import ValidationError
55
from django.forms import fields_for_model
@@ -95,18 +95,25 @@ def errors(self) -> dict:
9595
def is_valid(self) -> bool:
9696
return not self.errors
9797

98-
def add_error(self, field: Union[str, Tuple], errors: ValidationError):
98+
def add_error(self, field: Tuple, errors: ValidationError):
9999
if hasattr(errors, 'error_dict'):
100-
for item in errors.error_dict.values():
101-
for error in item:
100+
for key, items in errors.error_dict.items():
101+
for error in items:
102102
if isinstance(error, DetailValidationError):
103103
error.prepend(field)
104104
self.add_error(error.path, error)
105+
elif isinstance(error, ValidationError):
106+
self.add_error(field + (key, ), error)
105107
elif not hasattr(errors, 'message') and isinstance(errors.error_list, list):
106108
for item in errors.error_list:
107109
if isinstance(item, DetailValidationError):
108110
item.prepend(field)
109111
self.add_error(item.path, item)
112+
elif isinstance(item, ValidationError):
113+
path = field
114+
if hasattr(item, 'path'):
115+
path = field + item.path
116+
self.add_error(path, item)
110117
else:
111118
self._errors.append(
112119
DetailValidationError(errors, (field,) if isinstance(field, str) else field)
@@ -132,13 +139,13 @@ def full_clean(self):
132139
if hasattr(self, f"clean_{key}"):
133140
self.cleaned_data[key] = getattr(self, f"clean_{key}")()
134141
except ValidationError as e:
135-
self.add_error(key, e)
142+
self.add_error((key, ), e)
136143
except (AttributeError, TypeError, ValueError):
137-
self.add_error(key, ValidationError(_("Invalid value")))
144+
self.add_error((key, ), ValidationError(_("Invalid value")))
138145
try:
139146
cleaned_data = self.clean()
140147
except ValidationError as e:
141-
self.add_error('$body', e)
148+
self.add_error(('$body', ), e)
142149
else:
143150
if cleaned_data is not None:
144151
self.cleaned_data = cleaned_data

β€Ždocs/tutorial.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ This process is much more simple than in classic Django form. It consists of:
8181
1. Iterating over form attributes:
8282
- calling `Field.clean(value)` method
8383
- calling `Form.clean_<field_name>` method
84-
- calling `Form.add_error(field_name, error)` in case of failures in clean methods
84+
- calling `Form.add_error((field_name, ), error)` in case of failures in clean methods
8585
- if field is marked as dirty, normalized attribute is saved to `Form.clean_data` property
8686
2. Calling `Form.clean` method which returns final normalized values which will be presented in `Form.clean_data`
8787
(feel free to override it, by default does nothing, useful for conditional validation, you can still add errors u
@@ -95,7 +95,7 @@ Validation errors are presented for each field in `Form.errors: List[ValidationE
9595
As was mentioned above, you can extend property validation or normalisation by creating form method like
9696
`clean_<property_name>`. You can add additional
9797
[ValidationError](https://docs.djangoproject.com/en/3.1/ref/forms/validation/#raising-validationerror)
98-
objects using `Form.add_error(field: Union[str, Tuple], error: ValidationError)` method. Result is final normalised
98+
objects using `Form.add_error(field: Tuple, error: ValidationError)` method. Result is final normalised
9999
value of the attribute.
100100

101101
```python
@@ -109,7 +109,7 @@ class BookForm(Form):
109109

110110
def clean_title(self):
111111
if self.cleaned_data['title'] == "The Hitchhiker's Guide to the Galaxy":
112-
self.add_error('title', ValidationError("Too cool!", code='too-cool'))
112+
self.add_error(('title', ), ValidationError("Too cool!", code='too-cool'))
113113
return self.cleaned_data['title'].upper()
114114

115115
def clean(self):

0 commit comments

Comments
Β (0)