Senior Software Architect
Django is powerful web framework, but with power comes responsibility. In this article, we will cover common mistakes that are even seasoned Django developers make, yet most successful Django projects need to deal with these sooner or later.
Django has a lot of features out of the box and even more in third party packages. Try "Googling" a problem you want to solve before you write something - there’s probably a feature-rich solution that already exists.
Here is a short sample of interesting packages just from the first two pages of the listing:
Django is a loosely coupled framework and it doesn’t require you to build web applications in any particular way. Seasoned Django developers, however, have a standard way of doing things.
The fundamental unit of a Django web application is a Django project which is made up of one or more apps. A Django app is a self-contained package that should only do one thing. For example a blog, a membership app or an event calendar.
Django apps can contain Python modules, Django-specific modules (views, URLs, models, forms, etc), static files, database migrations, management commands, unit tests, and more.
You should divide your project into small, reusable applications using simple logic.
\ecommerce_project <= This is your Django project \cart <= This is a Django cart app \checkout <= This is a Django checkout app \products <= This is a Django products app db.sqlite3 <= Your project database manage.py <= Django project management utility
Using such a structure, related functionality will be closer together, allowing you and your team to see the bigger picture of your application more clearly. On top of that, you can export the application into another project and use it again, or even publish it on PyPi as an open-source module.
Django’s architecture can be described as a Model-Template-View (MTV) or Model-View-Template (MVT).
The model is where most of your business logic should go. It is defined in
and resides in the application directory. It also includes database queries that pass results to your view and template layers.
Views consist of code that deals with user interaction like form submission by the user and shaping results from the database to fit your template. It is defined in
If you don’t write your application logic in models and use views, this means you’ve written your code in a model based on the view. This makes the views “fat”, and the model “skinny.”
Models should be fat and views should be skinny.
Breaking logic into smaller models lets you use it numerous times from various sources. You will not have to copy-paste any code.
You can also unit-test your code since the logic is in one place.
Django's ORM often blamed for making too many queries, or unoptimized queries. But we see that happening with ORMs in other frameworks as well.
The real problem is we are often unaware of the performance problems and their sources. Once you find out what your bottlenecks are, you’ll be able to choose the right approach to address them.
There’s a lot you can do from here, but most likely it’ll be:
django-debug-toolbar is an amazing debugging tool. You can use it to track down performance problems in SQL queries, requests, templates, cache, etc. This little package will help you identify the problems quickly. I highly recommend using it.
Since queries can't use computed columns and adding a real column is only a "make migrations" away, often developers duplicate fields that represent the same data in different ways.
Pretty soon half of your Vehicles have
is_motorcycle == True
, and you're not sure which field to trust (hint: neither).
wheel_count == 4
With Django, you can refactor inconsistent properties like this with the
decorator. However, while the ORM allows you to access columns as properties, the reverse is not true, so you have to manually refactor every query.
Even seasoned Django developers forget about indexes. Please, do add indexes to your models! On the other hand, do not index everything, as it will slow down inserts, updates, and deletes.
As a general rule, you want an index on anything you will use to filter or join on. Analyze your QuerySets to determinate where indexes are needed.
Django models can be associated with one or more “forms”, which used to create and update model instances. Forms have a lot of default behavior, particularly validation, which is controlled by the properties of the model. In fact, many properties of the model exist only to control the forms' default behavior.
Many Django developers forget the model can be modified not only through its form. They also forget about keeping track of which constraints are where. Non-null? That's on the model.
Define choices on a field, explicitly enumerating what values it can have? That's on the form.
Uniqueness? On the model.
And so on.
This inconsistent validation results in bad user experience: forms, pre-populated with the existing data for an object, that cannot be submitted because the existing data is invalid.
Django was crafted to help build software as quickly as possible. However, when rushing with adding new features it is easy to forget something or loose the big picture.
In this article, we will looked at some common mistakes that are often made by Django developers and ways to avoid them.
This checklist should useful even if you’re a skilled Django developer because mistakes, like not adding indexes on models or inconsistent data validation, aren’t just limited to new developers.
Create your free account to unlock your custom reading experience.