django validation - simple is better than complex · 2. django view 3. form / drf serializer 4....
TRANSCRIPT
![Page 1: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/1.jpg)
DJANGO VALIDATION
![Page 2: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/2.jpg)
LOÏC BISTUER
‣ @loic84 on IRC and Twitter
‣ I work at the World Food Programme
‣ Django core developer since 2014
‣ Mostly contribute to Forms and ORM
![Page 3: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/3.jpg)
MAIN CONCERNS WITH VALIDATION
![Page 4: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/4.jpg)
MAIN CONCERNS WITH VALIDATION
1. Enforcement
![Page 5: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/5.jpg)
MAIN CONCERNS WITH VALIDATION
1. Enforcement
2. User Experience
![Page 6: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/6.jpg)
MAIN CONCERNS WITH VALIDATION
1. Enforcement
2. User Experience
3. Performance
![Page 7: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/7.jpg)
MAIN CONCERNS WITH VALIDATION
1. Enforcement
2. User Experience
3. Performance
4. Convenience
![Page 8: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/8.jpg)
MAIN CONCERNS WITH VALIDATION
1. Enforcement
2. User Experience
3. Performance
4. Convenience
![Page 9: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/9.jpg)
MAIN CONCERNS WITH VALIDATION
1. Enforcement
2. User Experience
3. Performance
4. Convenience
![Page 10: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/10.jpg)
MAIN CONCERNS WITH VALIDATION
1. Enforcement
2. User Experience
3. Performance
4. Convenience
![Page 11: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/11.jpg)
WHERE TO VALIDATE DATA
![Page 12: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/12.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
![Page 13: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/13.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
![Page 14: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/14.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
![Page 15: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/15.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
![Page 16: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/16.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Good for UX
![Page 17: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/17.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Good for UX
👍 Works offline
![Page 18: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/18.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Good for UX
👍 Works offline
👎 Need to keep in sync with server validation
![Page 19: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/19.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
![Page 20: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/20.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👎 Not designed for the task
![Page 21: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/21.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👎 Not designed for the task
👎 Easy to circumvent
![Page 22: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/22.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
![Page 23: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/23.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
![Page 24: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/24.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👎 Easy to circumvent
![Page 25: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/25.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👎 Easy to circumvent
![Page 26: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/26.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
![Page 27: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/27.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
![Page 28: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/28.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👎 Doesn’t run by default
![Page 29: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/29.jpg)
ENFORCE MODEL VALIDATION
class ValidateModelMixin(object):
def save(self, *args, **kwargs): # Run model validation. self.full_clean()
super(ValidateModelMixin, self).save(*args, **kwargs)
![Page 30: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/30.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👎 Doesn’t run by default
👍 Harder to circumvent if triggered from the `save() ̀ method
![Page 31: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/31.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👎 Doesn’t run by default
👍 Harder to circumvent if triggered from the `save() ̀ method
👎 Not always accessible
![Page 32: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/32.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👎 Doesn’t run by default
👍 Harder to circumvent if triggered from the `save() ̀ method
👎 Not always accessible
👎 Redundant
![Page 33: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/33.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👎 Doesn’t run by default
👍 Harder to circumvent if triggered from the `save() ̀ method
👎 Not always accessible
👎 Redundant
👎 Breaks expectations
![Page 34: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/34.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
![Page 35: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/35.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
![Page 36: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/36.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👍 Always enforced
![Page 37: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/37.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👍 Always enforced
👍 Performance!
![Page 38: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/38.jpg)
PERFORMANCE OF MODEL VALIDATION
def validate_title(title): if title == 'boom': raise ValidationError('Boom!', code='boom')
class Article(models.Model): title = models.CharField( max_length=42, validators=[validate_title], )
![Page 39: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/39.jpg)
PERFORMANCE OF MODEL VALIDATION
def validate_title(title): if title == 'boom': raise ValidationError('Boom!', code='boom')
class Article(models.Model): title = models.CharField( max_length=42, validators=[validate_title], )
with transaction.atomic(): for i in range(1000000): article = Article(title=str(i)) article.full_clean() article.save()
![Page 40: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/40.jpg)
PERFORMANCE OF MODEL VALIDATION
def validate_title(title): if title == 'boom': raise ValidationError('Boom!', code='boom')
class Article(models.Model): title = models.CharField( max_length=42, validators=[validate_title], )
ALTER TABLE article ADD CHECK(title <> 'boom');
Article.objects.bulk_create( Article(title=str(i)) for i in range(1000000) )
![Page 41: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/41.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👍 Always enforced
👍 Performance!
👎 Backend specific
![Page 42: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/42.jpg)
DATABASE CHECK CONSTRAINTS
class Article(models.Model): title = models.CharField(max_length=42)
class Meta: indexes = [ models.Constraint( [F('title') != Value('boom')], name='expression_check', ), ]
![Page 43: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/43.jpg)
DATABASE CHECK CONSTRAINTS
class Article(models.Model): title = models.CharField(max_length=42)
class Meta: indexes = [ models.Constraint( [F('title') != Value('boom')], name='expression_check', ), ]
ALTER TABLE article ADD CHECK(title <> 'boom');
![Page 44: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/44.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👍 Always enforced
👍 Performance!
👎 Backend specific
👎 Harder to write
![Page 45: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/45.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👍 Always enforced
👍 Performance!
👎 Backend specific
👎 Harder to write
👎 Harder to audit
![Page 46: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/46.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
👍 Designed for the task
👍 Always enforced
👍 Performance!
👎 Backend specific
👎 Harder to write
👎 Harder to audit
👎 Harder to maintain
![Page 47: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/47.jpg)
WHERE TO VALIDATE DATA
1. Frontend
‣ JavaScript
‣ HTML5 & Browser
‣ Native code / frameworks
2. Django View
3. Form / DRF Serializer
4. Model
5. Database
![Page 48: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/48.jpg)
FIELD VALIDATION
![Page 49: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/49.jpg)
FIELD DECLARATION
‣ Type validation ‣ class Field(object):
‣ class CharField(Field):
‣ class IntegerField(Field):
‣ class DateField(Field):
‣ etc.
![Page 50: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/50.jpg)
FIELD DECLARATION
‣ Presence validation class Field(object): def __init__(self, required=True, ...): self.required = required
...
class Field(object): def __init__(self, blank=False, ...): self.blank = blank
...
![Page 51: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/51.jpg)
FIELD DECLARATION
‣ Bounds validation class CharField(Field): def __init__(self, max_length=None, min_length=None): ...
class IntegerField(Field): def __init__(self, max_value=None, min_value=None): ...
![Page 52: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/52.jpg)
FIELD DECLARATION
‣ Choice validation # django.forms.fields
class ChoiceField(forms.Field): def __init__(self, choices=()): ...
# django.db.models.fields
class Field(object): def __init__(self, choices=()): ...
![Page 53: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/53.jpg)
FIELD DECLARATION
‣ Format validation class RegexField(CharField): def __init__(self, regex, ...): ...
class DateField(Field): def __init__(self, input_formats, ...) ...
![Page 54: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/54.jpg)
FIELD DECLARATION
‣ Format validation class RegexField(CharField): def __init__(self, regex, ...): ...
class DateField(Field): def __init__(self, input_formats, ...) ...
class EmailField(CharField): default_validators = [validate_email]
class SlugField(CharField): default_validators = [validate_slug]
![Page 55: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/55.jpg)
FIELD DECLARATION
‣ Uniqueness validation class Field(object): def __init__(self, unique=False, unique_for_date=None, unique_for_month=None, unique_for_year=None, ...): ...
![Page 56: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/56.jpg)
FIELD DECLARATION
‣ Field validators class Field(object): default_validators = []
def __init__(self, validators=(), ...): self.validators = list(itertools.chain( self.default_validators, validators))
![Page 57: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/57.jpg)
FUNCTION-BASED VALIDATOR
def validate_even(value): if value % 2 != 0: raise ValidationError( _('%(value)s is not an even number'), params={'value': value}, )
IntegerField(validators=[validate_even])
![Page 58: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/58.jpg)
CLASS-BASED VALIDATOR
class MultipleOf(object): def __init__(self, base): self.base = base
def __call__(self, value): if value % self.base != 0: raise ValidationError( _('Field must be a multiple of %(base)d.'), params={'base': self.base, 'value': value}, )
IntegerField(validators=[MultipleOf(42)])
![Page 59: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/59.jpg)
CLASS-BASED VALIDATOR
from django.utils.deconstruct import deconstructible
@deconstructible class MultipleOf(object): def __init__(self, base): self.base = base
def __call__(self, value): if value % self.base != 0: raise ValidationError( _('Field must be a multiple of %(base)d.'), params={'base': self.base, 'value': value}, )
def __eq__(self, other): return ( isinstance(other, self.__class__) and self.base == other.base )
![Page 60: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/60.jpg)
PARTIAL-BASED VALIDATOR
import functools
def multiple_of(base, value): if value % base != 0: raise ValidationError( _('Field must be a multiple of %(base)d.'), params={'base': base, 'value': value}, )
multiple_of_42 = functools.partial(multiple_of, 42)
IntegerField(validators=[multiple_of_42])
![Page 61: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/61.jpg)
FIELD DECLARATION
‣ Error messages class Field(object): def __init__(self, error_messages=None, ...): ...
![Page 62: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/62.jpg)
FIELD DECLARATION
‣ Error messages class Field(object): default_error_messages = { 'required': _('This field is required.'), }
def __init__(self, error_messages=None, ...): messages = {} for c in reversed(self.__class__.__mro__): messages.update( getattr(c, 'default_error_messages', {})) messages.update(error_messages or {}) self.error_messages = messages
...
![Page 63: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/63.jpg)
FIELD VALIDATION CYCLE
![Page 64: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/64.jpg)
FIELD VALIDATION CYCLE
‣ Field.clean() def clean(self, value): value = self.to_python(value) self.validate(value) self.run_validators(value) return value
![Page 65: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/65.jpg)
FIELD VALIDATION CYCLE
‣ Field.clean() def clean(self, value): value = self.to_python(value) self.validate(value) self.run_validators(value) return value
![Page 66: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/66.jpg)
FIELD VALIDATION CYCLE
‣ Field.clean() def clean(self, value): value = self.to_python(value) self.validate(value) self.run_validators(value) return value
![Page 67: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/67.jpg)
FIELD VALIDATION CYCLE
‣ Field.validate() def validate(self, value): if value in self.empty_values and self.required: raise ValidationError( self.error_messages['required'], code='required', )
![Page 68: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/68.jpg)
FIELD VALIDATION CYCLE
‣ Field.clean() def clean(self, value): value = self.to_python(value) self.validate(value) self.run_validators(value) return value
![Page 69: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/69.jpg)
FIELD VALIDATION CYCLE
‣ Field.run_validators() def run_validators(self, value): if value in self.empty_values: return
errors = [] for validator in self.validators: try: validator(value) except ValidationError as e: if hasattr(e, 'code') and e.code in self.error_messages: e.message = self.error_messages[e.code] errors.extend(e.error_list)
if errors: raise ValidationError(errors)
![Page 70: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/70.jpg)
FIELD VALIDATION CYCLE
‣ Field.run_validators() def run_validators(self, value): if value in self.empty_values: return
errors = [] for validator in self.validators: try: validator(value) except ValidationError as e: if hasattr(e, 'code') and e.code in self.error_messages: e.message = self.error_messages[e.code] errors.extend(e.error_list)
if errors: raise ValidationError(errors)
![Page 71: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/71.jpg)
FIELD VALIDATION CYCLE
‣ Field.clean() def clean(self, value): value = self.to_python(value) self.validate(value) self.run_validators(value) return value
![Page 72: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/72.jpg)
FIELD VALIDATION CYCLE
‣ Field.clean() class CharField(Field): def __init__(self, max_length, min_length, ...): ... self.max_length = max_length self.min_length = min_length self.validators.append( validators.MinLengthValidator(min_length)) self.validators.append( validators.MaxLengthValidator(max_length))
![Page 73: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/73.jpg)
VALIDATION ERROR
![Page 74: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/74.jpg)
ANATOMY OF VALIDATION ERROR
class ValidationError(Exception):
def __init__(self, message, code=None, params=None): ...
![Page 75: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/75.jpg)
ANATOMY OF VALIDATION ERROR
class ValidationError(Exception):
def __init__(self, message, code=None, params=None): ...
ValidationError("Foo")
![Page 76: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/76.jpg)
ANATOMY OF VALIDATION ERROR
class ValidationError(Exception):
def __init__(self, message, code=None, params=None): ...
ValidationError("Foo")
ValidationError(["Foo", "Bar"])
![Page 77: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/77.jpg)
ANATOMY OF VALIDATION ERROR
class ValidationError(Exception):
def __init__(self, message, code=None, params=None): ...
ValidationError("Foo")
ValidationError(["Foo", "Bar"])
ValidationError({ "field1": ["Foo", "Bar"], "field2": "Baz", })
![Page 78: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/78.jpg)
ANATOMY OF VALIDATION ERROR
class ValidationError(Exception):
def __init__(self, message, code=None, params=None): ...
ValidationError([ "Bar", ValidationError("Foo"), ])
![Page 79: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/79.jpg)
ANATOMY OF VALIDATION ERROR
class ValidationError(Exception):
def __init__(self, message, code=None, params=None): ...
ValidationError({ "field1": ValidationError([ ValidationError("Foo"), ValidationError("Bar"), ]), })
![Page 80: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/80.jpg)
ANATOMY OF VALIDATION ERROR
class ValidationError(Exception): def __init__(self, message, code=None, params=None): ...
if isinstance(message, dict): self.error_dict = {...}
elif isinstance(message, list): self.error_list = [...]
else: self.message = message self.code = code self.params = params self.error_list = [self]
![Page 81: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/81.jpg)
ANATOMY OF VALIDATION ERROR
class ValidationError(Exception): def __init__(self, message, code=None, params=None): ...
if isinstance(message, dict): self.error_dict = {...}
elif isinstance(message, list): self.error_list = [...]
else: self.message = message self.code = code self.params = params self.error_list = [self]
![Page 82: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/82.jpg)
RAISING VALIDATION ERRORS
raise ValidationError("Invalid value: %s" % 42)
![Page 83: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/83.jpg)
RAISING VALIDATION ERRORS
from django.utils.translation import ugettext as _
raise ValidationError(_("Invalid value: %s") % 42)
![Page 84: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/84.jpg)
RAISING VALIDATION ERRORS
from django.utils.translation import ugettext as _
raise ValidationError( _("Invalid value: %s") % 42, code='invalid', )
![Page 85: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/85.jpg)
RAISING VALIDATION ERRORS
from django.utils.translation import ugettext as _
raise ValidationError( _("Invalid value: %s"), code='invalid', params=42, )
![Page 86: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/86.jpg)
RAISING VALIDATION ERRORS
from django.utils.translation import ugettext as _
raise ValidationError( _("Invalid value: %(value)s"), code='invalid', params={'value': 42}, )
![Page 87: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/87.jpg)
RAISING VALIDATION ERRORS
from django.utils.translation import ugettext as _
raise ValidationError( message=_("%(model_name)s with this %(field_labels)s " "already exists."), code='unique_together', params={ 'model': self, 'model_class': model_class, 'model_name': verbose_name), 'unique_check': unique_check, }, )
![Page 88: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/88.jpg)
FORM VALIDATION
![Page 89: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/89.jpg)
TRIGGERING FORM VALIDATION
‣ Form.is_valid() def is_valid(self): return self.is_bound and not self.errors
![Page 90: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/90.jpg)
TRIGGERING VALIDATION
‣ Form.is_valid() def is_valid(self): return self.is_bound and not self.errors
‣ Form.errors @property def errors(self): if self._errors is None: self.full_clean() return self._errors
![Page 91: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/91.jpg)
TRIGGERING VALIDATION
‣ Form.is_valid() def is_valid(self): return self.is_bound and not self.errors
‣ Form.errors @property def errors(self): if self._errors is None: self.full_clean() return self._errors
‣ Form.full_clean()
![Page 92: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/92.jpg)
FORM VALIDATION CYCLE
‣ Form.full_clean() def full_clean(self): self._errors = ErrorDict() self.cleaned_data = {}
self._clean_fields() self._clean_form() self._post_clean()
![Page 93: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/93.jpg)
FORM VALIDATION CYCLE
‣ Form.full_clean() def full_clean(self): self._errors = ErrorDict() self.cleaned_data = {}
self._clean_fields() self._clean_form() self._post_clean()
![Page 94: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/94.jpg)
FORM VALIDATION CYCLE
‣ Form.full_clean() def full_clean(self): self._errors = ErrorDict() self.cleaned_data = {}
self._clean_fields() self._clean_form() self._post_clean()
![Page 95: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/95.jpg)
FORM VALIDATION CYCLE
‣ Form._clean_fields() def _clean_fields(self): for name, field in self.fields.items(): value = field.widget.value_from_datadict( self.data, self.files, self.add_prefix(name))
![Page 96: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/96.jpg)
FORM VALIDATION CYCLE
‣ Form._clean_fields() def _clean_fields(self): for name, field in self.fields.items(): value = field.widget.value_from_datadict( self.data, self.files, self.add_prefix(name))
try: value = field.clean(value) self.cleaned_data[name] = value
![Page 97: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/97.jpg)
FORM VALIDATION CYCLE
‣ Form._clean_fields() def _clean_fields(self): for name, field in self.fields.items(): value = field.widget.value_from_datadict( self.data, self.files, self.add_prefix(name))
try: value = field.clean(value) self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name): value = getattr(self, 'clean_%s' % name)() self.cleaned_data[name] = value
![Page 98: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/98.jpg)
FORM VALIDATION CYCLE
‣ Form._clean_fields() def _clean_fields(self): for name, field in self.fields.items(): value = field.widget.value_from_datadict( self.data, self.files, self.add_prefix(name))
try: value = field.clean(value) self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name): value = getattr(self, 'clean_%s' % name)() self.cleaned_data[name] = value
except ValidationError as e: self.add_error(name, e)
![Page 99: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/99.jpg)
FORM VALIDATION CYCLE
‣ Form.full_clean() def full_clean(self): self._errors = ErrorDict() self.cleaned_data = {}
self._clean_fields() self._clean_form() self._post_clean()
![Page 100: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/100.jpg)
FORM VALIDATION CYCLE
‣ Form._clean_form() def _clean_form(self): try: cleaned_data = self.clean() except ValidationError as e: self.add_error(None, e) else: if cleaned_data is not None: self.cleaned_data = cleaned_data
![Page 101: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/101.jpg)
FORM VALIDATION CYCLE
‣ Form.full_clean() def full_clean(self): self._errors = ErrorDict() self.cleaned_data = {}
self._clean_fields() self._clean_form() self._post_clean()
‣ Form._post_clean() def _post_clean(self): pass
![Page 102: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/102.jpg)
FORM VALIDATION UTILS
‣ Form.add_error()
![Page 103: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/103.jpg)
FORM VALIDATION UTILS
‣ Form.add_error() def add_error(self, field, error): if not isinstance(error, ValidationError): error = ValidationError(error)
![Page 104: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/104.jpg)
FORM VALIDATION UTILS
‣ Form.add_error() def add_error(self, field, error): if not isinstance(error, ValidationError): error = ValidationError(error)
if hasattr(error, 'error_dict'): error = error.error_dict else: error = {field or NON_FIELD_ERRORS: error.error_list}
![Page 105: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/105.jpg)
FORM VALIDATION UTILS
‣ Form.add_error() def add_error(self, field, error): if not isinstance(error, ValidationError): error = ValidationError(error)
if hasattr(error, 'error_dict'): error = error.error_dict else: error = {field or NON_FIELD_ERRORS: error.error_list}
for field, error_list in error.items(): if field not in self.errors: self._errors[field] = self.error_class() self._errors[field].extend(error_list)
![Page 106: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/106.jpg)
FORM VALIDATION UTILS
‣ Form.add_error() def add_error(self, field, error): if not isinstance(error, ValidationError): error = ValidationError(error)
if hasattr(error, 'error_dict'): error = error.error_dict else: error = {field or NON_FIELD_ERRORS: error.error_list}
for field, error_list in error.items(): if field not in self.errors: self._errors[field] = self.error_class() self._errors[field].extend(error_list)
if field in self.cleaned_data: del self.cleaned_data[field]
![Page 107: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/107.jpg)
FORM VALIDATION UTILS
‣ Form.add_error() def add_error(self, field, error): if not isinstance(error, ValidationError): error = ValidationError(error)
if hasattr(error, 'error_dict'): error = error.error_dict else: error = {field or NON_FIELD_ERRORS: error.error_list}
for field, error_list in error.items(): if field not in self.errors: self._errors[field] = self.error_class() self._errors[field].extend(error_list)
if field in self.cleaned_data: del self.cleaned_data[field]
![Page 108: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/108.jpg)
FORM VALIDATION UTILS
‣ Form.add_error() def add_error(self, field, error): if not isinstance(error, ValidationError): error = ValidationError(error)
if hasattr(error, 'error_dict'): error = error.error_dict else: error = {field or NON_FIELD_ERRORS: error.error_list}
for field, error_list in error.items(): if field not in self.errors: self._errors[field] = self.error_class() self._errors[field].extend(error_list)
if field in self.cleaned_data: del self.cleaned_data[field]
![Page 109: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/109.jpg)
FORM VALIDATION UTILS
‣ Form.add_error() def add_error(self, field, error): if not isinstance(error, ValidationError): error = ValidationError(error)
if hasattr(error, 'error_dict'): error = error.error_dict else: error = {field or NON_FIELD_ERRORS: error.error_list}
for field, error_list in error.items(): if field not in self.errors: self._errors[field] = self.error_class() self._errors[field].extend(error_list)
if field in self.cleaned_data: del self.cleaned_data[field]
![Page 110: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/110.jpg)
FORM VALIDATION UTILS
‣ Form.errors class ErrorDict(dict):
def as_ul(self): ...
def as_text(self): ...
def as_data(self): ...
def as_json(self, escape_html=False): ...
![Page 111: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/111.jpg)
FORM VALIDATION UTILS
‣ Form.errors['field_name'] class ErrorList(list):
def as_ul(self): ...
def as_text(self): ...
![Page 112: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/112.jpg)
FORM VALIDATION UTILS
‣ Form.errors['field_name'] class ErrorList(UserList, list):
def __contains__(self, item): return item in list(self)
def __eq__(self, other): return list(self) == other
def __ne__(self, other): return list(self) != other
def __getitem__(self, i): error = self.data[i] if isinstance(error, ValidationError): return list(error)[0] return force_text(error)
![Page 113: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/113.jpg)
FORM VALIDATION UTILS
‣ Form.errors['field_name'] class ErrorList(UserList, list):
def as_data(self): return ValidationError(self.data).error_list
def get_json_data(self): errors = [] for error in self.as_data(): errors.append({ 'message': list(error)[0], 'code': error.code or '', }) return errors
def as_json(self): return json.dumps(self.get_json_data())
![Page 114: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/114.jpg)
FORM VALIDATION UTILS
‣ Form.has_error() def has_error(self, field, code=None): if code is None: return field in self.errors
if field in self.errors: for error in self.errors.as_data()[field]: if error.code == code: return True
return False
![Page 115: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/115.jpg)
FORM VALIDATION UTILS
class ValidationError(Exception):
def __str__(self): if hasattr(self, 'error_dict'): return repr(dict(self)) return repr(list(self))
>>> str(ValidationError("Some error...")) "[u'Some error...']"
![Page 116: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/116.jpg)
FORM VALIDATION UTILS
class ValidationError(Exception):
def __str__(self): if hasattr(self, 'error_dict'): return repr(dict(self)) elif not hasattr(self, 'code'): return repr(list(self)) else: return list(self)[0]
>>> str(ValidationError("Some error...")) "Some error..."
![Page 117: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/117.jpg)
MODEL VALIDATION
![Page 118: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/118.jpg)
MODEL VALIDATION INSPIRED BY DJANGO’S FORM VALIDATION.
Django 1.2 release notes
![Page 119: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/119.jpg)
TRIGGERING MODEL VALIDATION
‣ Model.full_clean() try: article.full_clean() except ValidationError: is_valid = False else: is_valid = True
![Page 120: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/120.jpg)
MODEL VALIDATION CYCLE
‣ Model.full_clean() def full_clean(self, exclude=None, validate_unique=True): errors = {}
...
if errors: raise ValidationError(errors)
![Page 121: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/121.jpg)
MODEL VALIDATION CYCLE
‣ Model.full_clean() def full_clean(self, exclude=None, validate_unique=True): ...
try: self.clean_fields(exclude=exclude) except ValidationError as e: errors = e.update_error_dict(errors)
![Page 122: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/122.jpg)
MODEL VALIDATION CYCLE
‣ Model.full_clean() def full_clean(self, exclude=None, validate_unique=True): ...
try: self.clean() except ValidationError as e: errors = e.update_error_dict(errors)
![Page 123: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/123.jpg)
MODEL VALIDATION CYCLE
‣ Model.full_clean() def full_clean(self, exclude=None, validate_unique=True): ...
try: self.clean() except ValidationError as e: errors = e.update_error_dict(errors)
‣ Model.clean() def clean(self): pass
![Page 124: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/124.jpg)
MODEL VALIDATION CYCLE
‣ Model.full_clean() def full_clean(self, exclude=None, validate_unique=True): ...
if validate_unique: for name in errors.keys(): if name not in exclude: exclude.append(name)
try: self.validate_unique(exclude=exclude) except ValidationError as e: errors = e.update_error_dict(errors)
![Page 125: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/125.jpg)
MODEL VALIDATION CYCLE
‣ Field.unique_for_date ALTER TABLE article ADD EXCLUDE USING GIST ( title WITH =, daterange(pub_date, pub_date, '[]') WITH && );
![Page 126: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/126.jpg)
MODEL VALIDATION CYCLE
‣ Field.unique_for_month ALTER TABLE article ADD EXCLUDE USING GIST ( title WITH =, daterange( date_trunc('month', pub_date::timestamp)::date, (date_trunc('month', pub_date::timestamp) + '1month - 1day')::date, '[]' ) WITH && );
![Page 127: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/127.jpg)
MODEL VALIDATION CYCLE
‣ Field.unique_for_year ALTER TABLE article ADD EXCLUDE USING GIST ( title WITH =, daterange( date_trunc('year', pub_date::timestamp)::date, (date_trunc('year', pub_date::timestamp) + '1year - 1day')::date, '[]' ) WITH && );
![Page 128: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/128.jpg)
MODEL VALIDATION CYCLE
‣ Model.full_clean() def full_clean(self, exclude=None, validate_unique=True): ...
if validate_unique: for name in errors.keys(): if name not in exclude: exclude.append(name)
try: self.validate_unique(exclude=exclude) except ValidationError as e: errors = e.update_error_dict(errors)
![Page 129: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/129.jpg)
MODELFORM VALIDATION
![Page 130: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/130.jpg)
MODELFORM VALIDATION CYCLE
‣ ModelForm._post_clean() def _post_clean(self): self.instance = construct_instance(...)
![Page 131: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/131.jpg)
MODELFORM VALIDATION CYCLE
‣ ModelForm._post_clean() def _post_clean(self): self.instance = construct_instance(...)
exclude = self._get_validation_exclusions()
![Page 132: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/132.jpg)
MODELFORM VALIDATION CYCLE
‣ ModelForm._post_clean() def _post_clean(self): self.instance = construct_instance(...)
exclude = self._get_validation_exclusions()
try: self.instance.full_clean( exclude=exclude, validate_unique=False) except ValidationError as e: self._update_errors(e)
![Page 133: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/133.jpg)
MODELFORM VALIDATION CYCLE
‣ ModelForm._post_clean() def _post_clean(self): self.instance = construct_instance(...)
exclude = self._get_validation_exclusions()
try: self.instance.full_clean( exclude=exclude, validate_unique=False) except ValidationError as e: self._update_errors(e)
![Page 134: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/134.jpg)
MODELFORM VALIDATION CYCLE
‣ ModelForm._post_clean() def _post_clean(self): self.instance = construct_instance(...)
exclude = self._get_validation_exclusions()
try: self.instance.full_clean( exclude=exclude, validate_unique=False) except ValidationError as e: self._update_errors(e)
if self._validate_unique: self.validate_unique()
![Page 135: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/135.jpg)
CLOSING WORDS
![Page 136: DJANGO VALIDATION - Simple is Better Than Complex · 2. Django View 3. Form / DRF Serializer 4. Model 5. Database! Designed for the task " Doesn’t run by default ! Harder to circumvent](https://reader030.vdocuments.mx/reader030/viewer/2022040906/5e7c0d2849ce657f3e6db57d/html5/thumbnails/136.jpg)
THANK YOU