1 | class _ModelCleanWorkaroundMixin(object):
|
---|
2 | """
|
---|
3 | Mixin for Model subclasses that wish to raise ValidationErrors
|
---|
4 | in Model.clean() that target individual fields. As of Django 2.3
|
---|
5 | this is not possible, due to <https://code.djangoproject.com/ticket/16986>.
|
---|
6 | """
|
---|
7 |
|
---|
8 | # Workaround for: https://code.djangoproject.com/ticket/16986
|
---|
9 | def clean_fields(self, **kwargs):
|
---|
10 | try:
|
---|
11 | super(_ModelCleanWorkaroundMixin, self).clean_fields(**kwargs)
|
---|
12 | except ValidationError as e1:
|
---|
13 | if not hasattr(e1, 'message_dict'):
|
---|
14 | e1.message_dict = {NON_FIELD_ERRORS: e1.messages}
|
---|
15 | else:
|
---|
16 | e1 = None
|
---|
17 |
|
---|
18 | try:
|
---|
19 | # If not for this workaround, this method would be called clean()
|
---|
20 | self.clean_self()
|
---|
21 | except ValidationError as e2:
|
---|
22 | pass
|
---|
23 | else:
|
---|
24 | e2 = None
|
---|
25 |
|
---|
26 | if e1 and e2:
|
---|
27 | raise ValidationError(dict(e1.message_dict, **e2.message_dict))
|
---|
28 | elif e1 and not e2:
|
---|
29 | raise e1
|
---|
30 | elif not e1 and e2:
|
---|
31 | raise e2
|
---|
32 |
|
---|
33 | def _createLatitudeField():
|
---|
34 | return models.DecimalField(max_digits=8, decimal_places=6,
|
---|
35 | validators=[
|
---|
36 | validators.MinValueValidator(Decimal('-90.000000')),
|
---|
37 | validators.MaxValueValidator(Decimal('90.000000')),
|
---|
38 | ])
|
---|
39 |
|
---|
40 | def _createLongitudeField():
|
---|
41 | return models.DecimalField(max_digits=9, decimal_places=6,
|
---|
42 | validators=[
|
---|
43 | validators.MinValueValidator(Decimal('-180.000000')),
|
---|
44 | validators.MaxValueValidator(Decimal('180.000000')),
|
---|
45 | ])
|
---|
46 |
|
---|
47 |
|
---|
48 | class Region(_ModelCleanWorkaroundMixin, models.Model):
|
---|
49 | south = _createLatitudeField()
|
---|
50 | west = _createLongitudeField()
|
---|
51 | north = _createLatitudeField()
|
---|
52 | east = _createLongitudeField()
|
---|
53 |
|
---|
54 | def clean_self(self):
|
---|
55 | message_dict = defaultdict(list)
|
---|
56 |
|
---|
57 | if self.west and self.east and (not self.west <= self.east):
|
---|
58 | message_dict['south'].append('Southwest pin must be west of the northeast pin.')
|
---|
59 | if self.south and self.north and (not self.south <= self.north):
|
---|
60 | message_dict['south'].append('Southwest pin must be south of the northeast pin.')
|
---|
61 |
|
---|
62 | if len(message_dict):
|
---|
63 | raise ValidationError(message_dict)
|
---|