Django and Django Rest Framework are great tools for creating REST applications. However, when your application grow up keeping the technical debt low is really challenging. I have suffered these kind of situations many times using Django.
The goal of this article is sharing with you the pains I have found getting bigger and more complex my applicaitons.
This principle is used many times by the Django ecosystem, avoiding duplications in your codes is great, but you need to understand the necessities you are solving. Two different features may have some common parts now, but they might change in the future, understanding when and how your code should be isolated using different components would be the perfect solution, in order to avoid future problems (SRP).
In order to boost your productivity, Django (and its ecosystem) exceed the usage of DRY principle, it save you a lot of work, but the sideways are it generate many couples between different parts of your applications which will generate you future. We will explore when this principle is overused.
The Django models are one of the core features of any Django Application, they provide you access to the database, and they save you a lot of work. Here Django use the models as core entity to avoid you repeat the same them in other components. Despite the good intention, coupling your business entities with your database entities is not a good path you want to walk.
What happen when your database change? you will need to change your models and your business core.
As well there are other Django and DRF components which base part of their features on these models, such as: ModelForms, ModelSerializers, ModelViewsets…
These components have different mission, not only store information or work business data, DAMN IT we have just coupled our database to the whole application (a little messy)
Furthermore you are able to use your models from any app of your project, so when you change any model, you probably are affecting things which shouldn’t be, as well as breaking business use-cases in other places, so… hell I hope you have a high test coverage to catch it, before going to production.
Django Model dependency diagram with two applications
Recap, using Django models you are coupling many components of your project, and likely you will lose track which are using them, business, representation, data… If you have many features to maintain good luck!
Django Serializers are one of the most useful parts of the DRF library, they allow you serialize different kind of information without sweat, but we must use them carefully, if you mix different kind of entities and start nesting serializers, it will become messy.
The DRY principle invite use to reuse serializers in many use-cases, hoping the business use case is not going to change never…. After a few weeks we have started using those serializers with many other endpoints, and insider another serializers. Refactor the serializer is now an epic tasks. Don’t hear DRY here.
If the previous situation is tedious to resolve, when you add the complexity of the
ModelSerializer it becomes almost impossible to solve. The
ModelSerializer couple the representation logic to the database. Then, when your representation, or you database change you are in problems.
This might become the
ModelSerializer the most terrible thing in the Django ecosystem.
Trust me, NESTING MODEL SERIALIZERS IS NOT A GOOD IDEA, querys to your database will get out under control quickly.
DRF Views are quiet good tools to handle the income requests of your application.
The first problem appearear with GenericViews. Those views try to save you tons of work using a few attributes.
The queryset attribute is the most harmful one, tie your view to the database, and that’s not good. As well as It encourages you to custom the queryset for each use-case using
get_queryset method. I discourage the use of this method, when you handle many use cases in the same view is complicated understand which data you want to retrieve each time.
The serializer_class attribute is useful at the beginning when you need a new serializer for each use case this will end up being a torture (same serializer with dynamics fields is worse).
One of the coolest features of DRF, at the beginning, are the filters, they allow you filter easily your set of data, and they are able to handle the most use cases. However when the fields are custom created as annotations, or nested filtering is necessary it will be much difficult to handle.
Django Views try to centralize all the possible logic inside the views, and it end getting too much logic you need to handle in the same place, with many conditions and no much code, but too much possible pitfalls. The nice views quickly become spaghetti code area.
GenericViews and family (Mixins, Viewsets, ModelViewsets…) are pretty nice when you don’t need custom features and many use-cases to handle, doing simple CRUDs is super easy, but when the features are hard you should look for another strategy.
Django and Django Rest Framework are amazing tools to create REST Applications super fast, in order to accomplish your impossible deadline. These advantages don’t come without Although sideways, to Django and DRF help you by coupling many parts of your application and generating many cool features on their own.
Structuring your application from the beginning of the project is an important part for creating a maintainable future. You can use different coding architectures and Design patterns to keep a robust and mantainable project.