title: Django DRY Model/Form/Serializer Validation
body: <p>I'm having some issues figuring out the best (read: DRY &amp; maintainable) place for introducing validation logic in Django, namely between models, forms, and DRF serializers.</p>
  
  <p>I've worked with Django for several years and have been following the various conventions for handling model, form, and REST API endpoint validation. I've tried a lot of variations for ensuring overall data integrity, but I've hit a bit of a stumbling block recently. Here is a brief list of what I've tried after looking through many articles, SO posts, and tickets:</p>
  
  <ol>
  <li><p>Validation at the model level; namely, ensuring all of my custom constraints are matched before calling <code>myModel.save()</code> by overriding <code>myModel.clean()</code> (as well as field-specific and unique together methods). To do this, I ensured <code>myModel.full_clean()</code> was called in <code>myForm.clean()</code> (for forms -- and the admin panel actually already does this) and <code>mySerializer.validate()</code> (for DRF serializers) methods.</p></li>
  <li><p>Validation at the form and serializer level, calling a shared method for maintainable, DRY code.</p></li>
  <li><p>Validation at the form and serializer level, with a distinct method for each to ensure maximum flexibility (i.e. for when forms and endpoints have different constraints).</p></li>
  </ol>
  
  <p>Method one seems the most intuitive to me for when forms and serializers have identical constraints, but is a bit messy in practice; first, data is automatically cleaned and validated by the form or serializer, then the model entity is instantiated, and more validation is run again -- which is a little convoluted and can get complicated.</p>
  
  <p>Method three is what Django Rest Framework recommends as of version 3.0; they eliminated a lot of their <code>model.save()</code> hooks and prefer to leave validation to the user-facing aspects of your application. This makes some sense to me, since Django's base <code>model.save()</code> implementation doesn't call <code>model.full_clean()</code> anyway.</p>
  
  <p>So, method two seems to be the best overall generalized outcome to me; validation lives in a distinct place -- before the model is ever touched -- and the codebase is less cluttered / more DRY due to the shared validation logic.</p>
  
  <p>Unfortunately, most of the trouble I've encountered is with getting Django Rest Framework's serializers to cooperate. All three approaches work well for forms, and in fact work well for most HTTP methods (most notably when POSTing for entity creation) -- but none seem to play well when updating an existing entity (PUT, PATCH).</p>
  
  <p>Long story short, it has proved rather difficult to validate incoming data when it is incomplete (but otherwise valid -- often the case for PATCH). The request data may only contain some fields -- those that contain different / new information -- and the model instance's existing information is maintained for all other fields. In fact, <a href="https://github.com/tomchristie/django-rest-framework/issues/4306" rel="noreferrer" title="DRF issues #4306">DRF issue #4306</a> perfectly sums up this particular challenge.</p>
  
  <p>I've also considered running custom model validation at the viewset level (after serializer.validated_data is populated and serializer.instance exists, but before serializer.save() is called), but I'm still struggling to come up with a clean, generalized approach due to the complexities of handling updates.</p>
  
  <p><strong>TL;DR</strong> Django Rest Framework makes it a bit hard to write clean, maintainable validation logic in an obvious place, especially for partial updates that rely on a blend of existing model data and incoming request data.</p>
  
  <p>I'd love to have some Django gurus weigh in on what they've gotten to work, because I'm not seeing any convenient solution.</p>
  
  <p>Thanks.</p>