Django models are not just for defining what columns will you into your database table. As well as setting fields as attributes of the class, you can also define methods.
This post will go through 4 kinds of methods you can use on your Django models and when to use them. These are:
- Overriding parent methods
- Custom methods
- Dunder methods
If you’re new to Django and want to build a better understanding of how models work, I recommend reading my beginner’s guide to Django models first.
Adding methods to your models allow you to add custom functionality to your model and keep your code DRY (Don’t Repeat Yourself). All the examples in this post are for a model called
Post , which is part of a blogging application.
You can find the full code for the post in this GitHub repository.
Model properties are similar to fields except they are not stored in the database. They are used when the value can be calculated from other fields.
For example, you are building a blog and you want to add an excerpt for each post. Let’s say in this case, you just want the first 150 characters of the post body.
A property is the best option here because the excerpt is calculated from the post body. Storing the excerpt in the database would be very inefficient because it would mean storing data twice.
The code defined in properties is ad-hoc. This means the code in
def excerpt(self) is only run when
post.excerpt is called.
Properties are defined by adding the
@property decorator above the method. Adding the decorator means you can access the property just like any other field on the model like this”
post.excerpt. You can leave out the decorator and still get the same result but you would have to add parentheses to access the excerpt like so:
@property def excerpt(self): character_limit = 150 if len(self.body) < character_limit: excerpt = self.body else: excerpt = self.body[:character_limit] + "..." return excerpt
What is self?
Self refers to a single instance of a class. If the class is called Post, then self refers to an individual post.
This is an example of object-orientated programming and is not specific to Django models- it is very common style of coding amongst Python programmers.
If you see a method belonging to a class where the first argument is
self, it means the method is designed to be applied to a single instance of the class.
post = Post(title="abc", body="abc") result = post.do_something()
If the only argument is
self, you don’t need to provide any arguments when calling the function. The value of
self will be the object the method was called from.
2. Override parent methods
Models work by inheriting from
django.db.models.Model. This base class contains a number of methods that provide the functionality for Django to detect models and propagate their properties to the database.
Sometimes, we may want to tweak those methods.
In my blog application, I have a field called
updated_date. Whenever the post is updated, I want
updated_date to store the date and time the change was made.
As I want to change the value
updated_date every time a post is saved, I can override the
However, I don’t want to take any functionality away from the base class’s original
save() method. I found the method in the source code and it’s 70 lines long, so copying and pasting the contents of the method isn’t a good idea. You could later update Django and have to copy the code all over again because the new version changed the code.
The best practice when overriding methods is to add your custom code is to use
super(). Instead of copying 70 lines of code from the parent class, I’ve added one line of code and it does exactly the same thing. Much neater!
super().save() does is call the
save() method of the parent class.
Now, every time I update a post, the date and time of the update is saved to the database.
def save(self, **kwargs): self.updated_date = datetime.now() super().save(**kwargs)
save method can take up to four optional keyword arguments. By using
**kwargs, we can pass the keyword arguments the
save function was called with without having to define them explicitly.
3. Custom methods
Custom methods are methods we can add to a model that are not defined on the parent class.
They are useful when you want to perform an operation on a model instance like a blog post.
In this example, I’ve written a method called
def publish(self):. All it does is set the published date, change the post status and save the post.
Custom methods should be used when you have a bit of code that operates on a single instance of a model. It is particularly important when that bit of code is used in multiple places, as it will keep your code DRY (Don’t Repeat Yourself).
I also find that it makes the code easier to read. In
views.py, I can now publish a post with one line of code:
def publish(self): self.published_date = datetime.now() self.status = "published" self.save()
def publish(request: HttpRequest, slug: str) -> HttpResponse: post = get_object_or_404(Post, slug=slug) post.publish() return redirect("index")
Examples of when a custom method could be useful
- You have a model called
Order. You could have a method called
place()to allow you to place an order with one line of code:
- You have a model called
Taskthat stores payloads to be sent to an API. Your model could have a method
submit()to submit the task.
4. Dunder methods
The final type of method are our dunder methods. These are methods that start and end with a double underscore. These are a feature of Python rather than Django specifically. The
__str__ method defines the string representation.
You can find the string representation for any object by calling
By default, Django sets the string on model instances which provide very little context about the object is about.
__str__ Django uses a default constructed from the model name and the object ID. ‘Post object (1)’ isn’t very helpful at all. You will notice this when you go into admin.
You can change it by defining
__str__ on your model:
def __str__(self): return self.title
>>> from blog.models import Post >>> post = Post.objects.first() >>> post <Post: Post object (1)> >>> str(post) 'Post object (1)' >>>
>>> post = Post.objects.first() >>> post <Post: How to Add CSS to a Django Project> >>> str(post) 'How to Add CSS to a Django Project' >>>
There are four kinds of model methods:
- Properties are used to define property that isn’t stored in the database. Instead they are calculated from other fields. Unlike custom methods, properties can be accessed without calling the method like a function.
- Overriding parent methods allow you to extend the functionality of Django’s base model. Using
super()in these methods is important, so you can add your own code without losing the method’s original functionality.
- Custom methods are useful when you have a function that operates on a single object. They can be used in scenarios like publishing a blog post with
def publish(self)or placing an order
- Dunder methods are native to Python. They provide small but useful features like defining the string representation of an object.
Choosing the correct model method will help keep your code DRY and give you the tools to add custom features to your model classes.