So far, you’ve used Django models mainly to define database structure. But models can do much more than just store data — they can also contain logic.
Django allows you to add:
This makes your models smarter, cleaner, and easier to maintain.
Instead of spreading logic across views and templates, you can centralize it inside your models — which is a best practice in Django.
By the end of this tutorial, you will understand:
@propertyYou should already know:
ForeignKey, etc.)A model method is simply a Python function defined inside a Django model.
It allows you to:
models.pyfrom django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
def short_content(self):
return self.content[:50]post = Post.objects.first()
print(post.short_content())<p>{{ post.short_content }}</p>👉 In templates, you don’t need parentheses.
__str__() MethodYou already used this, but it’s actually a model method.
def __str__(self):
return self.titleIt defines how the object appears:
Always include a meaningful __str__() method.
Model methods can contain real logic.
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.FloatField()
discount = models.FloatField(default=0)
def final_price(self):
return self.price - (self.price * self.discount / 100)product.final_price()<p>Price: {{ product.final_price }}</p>A property is a method that behaves like an attribute.
You define it using the @property decorator.
@propertyclass Product(models.Model):
name = models.CharField(max_length=100)
price = models.FloatField()
discount = models.FloatField(default=0)
@property
def final_price(self):
return self.price - (self.price * self.discount / 100)product.final_price # no parentheses<p>{{ product.final_price }}</p>| Feature | Method | Property |
|---|---|---|
| Syntax | obj.method() | obj.property |
| Use case | action / logic | computed value |
| Template usage | no parentheses | no parentheses |
👉 Rule of thumb:
from django.db import models
from django.utils.text import slugify
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def get_summary(self):
return self.content[:100]
@property
def is_long(self):
return len(self.content) > 500
def save(self, *args, **kwargs):
self.slug = slugify(self.title)
super().save(*args, **kwargs)post.get_summary()
post.is_longDjango templates allow you to use model methods directly.
<h2>{{ post.title }}</h2>
<p>{{ post.get_summary }}</p>
{% if post.is_long %}
<p>This is a long article</p>
{% endif %}Model methods become even more powerful when used with relationships.
class Category(models.Model):
name = models.CharField(max_length=100)
def post_count(self):
return self.posts.count()👉 assuming:
related_name='posts'category.post_count()<p>Posts: {{ category.post_count }}</p>class Order(models.Model):
total_price = models.FloatField()
tax = models.FloatField()
@property
def final_price(self):
return self.total_price + self.taxVery useful in templates.
class Post(models.Model):
content = models.TextField()
@property
def is_empty(self):
return len(self.content.strip()) == 0{% if post.is_empty %}
<p>No content</p>
{% endif %}You can format values easily.
class Product(models.Model):
price = models.FloatField()
def formatted_price(self):
return f"${self.price:.2f}"get_absolute_url()Very important built-in convention.
from django.urls import reverse
class Post(models.Model):
slug = models.SlugField()
def get_absolute_url(self):
return reverse('post_detail', kwargs={'slug': self.slug})save() MethodYou can customize saving behavior.
from django.utils.text import slugify
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(blank=True)
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args, **kwargs)Use model methods when:
Avoid putting:
For those, use:
@property for computed values__str__()@propertydef final_price(self):Then using:
product.final_price⚠️ This will not work as expected.
Models should not become too complex.
{{ product.final_price() }} ❌Correct:
{{ product.final_price }} ✔️class Product(models.Model):
name = models.CharField(max_length=100)
price = models.FloatField()
discount = models.FloatField(default=0)
stock = models.IntegerField()
@property
def final_price(self):
return self.price - (self.price * self.discount / 100)
@property
def in_stock(self):
return self.stock > 0
def short_name(self):
return self.name[:20]<h2>{{ product.short_name }}</h2>
<p>Price: {{ product.final_price }}</p>
{% if product.in_stock %}
<span>Available</span>
{% else %}
<span>Out of stock</span>
{% endif %}
In this tutorial, you learned:
@property simplifies access__str__() defines representationget_absolute_url() helps with routingsave() customizes behaviorUsing model methods and properties makes your Django applications cleaner, more organized, and easier to maintain.
A. A database field
B. A Python function inside a model
C. A template tag
D. A URL
@property do?A. Creates a database field
B. Converts a method into an attribute
C. Deletes a field
D. Creates a query
A. obj.property()
B. obj.property
C. property(obj)
D. obj.get_property()
A. display()
B. __str__()
C. show()
D. toString()
get_absolute_url() used for?A. Styling templates
B. Database queries
C. Returning a URL for an object
D. Authentication
Next tutorial:
Tutorial: Django Slugs and Clean URLs
You will learn how to create SEO-friendly URLs and improve your application’s structure.