In this post, I will share some tips to help you improve the design of your Django Models. Many of those tips are related to naming conventions, which can improve a lot the readability of your code.
The PEP8 is widely used in the Python ecosystem (Django included). So it’s a good idea to use it in your own projects.
Besides PEP8, I like to follow Django’s Coding Style which is a guideline for people writing code for inclusion in the Django code base itself.
Below, an overview of the items we are going to explore:
Naming Your Models
The model definition is a class, so always use CapWords convention (no underscores). E.g. User
, Permission
,
ContentType
, etc.
For the model’s attributes use snake_case. E.g. first_name
, last_name
, etc.
Example:
Always name your models using singular. Call it Company
instead of Companies
. A model definition is the
representation of a single object (the object in this example is a company), and not a collection of companies.
This usually cause confusion because we tend to think in terms of the database tables. A model will eventually be translated into a table. The table is correct to be named using its plural form because the table represents a collection of objects.
In a Django model, we can access this collection via Company.objects
. We can renamed the objects
attribute by
defining a models.Manager
attribute:
So with that we would access the collection of companies as Company.companies.filter(name='Google')
. But I usually
don’t go there. I prefer keeping the objects
attribute there for consistency.
Model Style Ordering
The Django Coding Style suggests the following order of inner classes, methods and attributes:
- If choices is defined for a given model field, define each choice as a tuple of tuples, with an all-uppercase name as a class attribute on the model.
- All database fields
- Custom manager attributes
class Meta
def __str__()
def save()
def get_absolute_url()
- Any custom methods
Example:
Reverse Relationships
related_name
The related_name
attribute in the ForeignKey
fields is extremely useful. It let’s us define a meaningful name
for the reverse relationship.
Rule of thumb: if you are not sure what would be the related_name
, use the plural of the model holding the ForeignKey
.
That means the Company
model will have a special attribute named employees
, which will return a QuerySet
with
all employees instances related to the company.
You can also use the reverse relationship to modify the company
field on the Employee
instances:
related_query_name
This kind of relationship also applies to query filters. For example, if I wanted to list all companies that employs people named ‘Vitor’, I could do the following:
If you want to customize the name of this relationship, here is how we do it:
Then the usage would be:
To use it consistently, related_name
goes as plural and related_query_name
goes as singular.
Blank and Null Fields
I’ve written about the differences between Blank and Null fields in another post, but I will try to summarize it here:
- Null: It is database-related. Defines if a given database column will accept null values or not.
- Blank: It is validation-related. It will be used during forms validation, when calling
form.is_valid()
.
Do not use null=True
for text-based fields that are optional. Otherwise, you will end up having two possible values
for “no data,” that is: None and an empty string. Having two possible values for “no data” is redundant. The
Django convention is to use the empty string, not NULL.
Example:
Further Reading
Models definition is one of the most important parts of your application. Something that makes all the difference is defining the field types properly. Make sure to review the Django models field types to know your options. You can also define custom field types.
If you are interested in code conventions, I suggest having a look on Django’s Coding Style. I’ve also published an tutorial about the flake8 library which helps you check for PEP8 issues in your code.
That’s it for today! You can also subscribe to my newsletter to receive updates from the blog.