Model Methods, __str__ & Meta
A model method is a function defined inside a Django model class that adds behaviour to each row, such as __str__ returning the readable label Django shows for that instance.
Learn Model Methods, __str__ & Meta in our free Django course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Django course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll add __str__ and custom instance methods, derive values with @property and get_absolute_url, run logic by overriding save(), and configure table-wide behaviour with class Meta — ordering, verbose names, constraints, and indexes.
Every Django model is a normal Python class, so you can give it methods. The most important one is __str__ : it returns the readable label Django uses in the admin, the shell, and anywhere an instance is printed. Beyond that, you add your own instance methods to express behaviour that belongs to a single row — like checking whether a post is recent.
Now str(post) returns the title instead of Post object (1) , and post.is_recent() answers a question about that specific row.
A @property turns a method into a read-only attribute, ideal for cheap derived values like a word count. get_absolute_url returns the canonical URL of an object, which Django and the admin use for "View on site" links. Overriding save() lets you run logic on every write — a classic use is auto-generating a slug from the title before calling super().save() .
The inner class Meta configures table-wide behaviour that is not a column. ordering sets the default sort, verbose_name and verbose_name_plural control display names, constraints add database-level rules such as UniqueConstraint , and indexes speed up common lookups.
Fill in the blank so save() sets the slug only when it is empty, mirroring the real if not self.slug: check before super().save() .
❌ My overridden save() runs but nothing is saved
You forgot to call the parent's save, so the row is never written to the database.
✅ Fix: end your save() with super().save(*args, **kwargs) .
Your __str__ returned something like an integer or a model instance.
✅ Fix: wrap it so it always returns text, e.g. return str(self.title) .
❌ The admin shows "Categorys" instead of "Categories"
Django guessed the plural by adding an "s", which is wrong for this word.
✅ Fix: set verbose_name_plural = "categories" in class Meta .
Reproduce ordering = ["-created_at", "title"] : sort newest first, and break ties alphabetically by title. Write the sort key.
Lesson complete — your models now have real behaviour!
You can write a readable __str__ , add custom instance methods, expose derived values with @property , return a canonical URL with get_absolute_url , run logic by overriding save() and calling super().save() , and configure class Meta with ordering, verbose names, constraints, and indexes.
🚀 Up next: QuerySet Deep Dive — query the rows your models describe with filters, lookups, and aggregation.
Practice quiz
What does __str__ return for a model instance?
- A query result
- The human-readable label for the instance
- The primary key
- An HTML page
Answer: The human-readable label for the instance. __str__ returns the readable label shown in admin, shell, and prints.
Without a custom __str__, how does a Post instance display?
- Its title
- Post object (1)
- An empty string
- An error
Answer: Post object (1). Without __str__ you see something like 'Post object (1)'.
What type must __str__ always return?
- An integer
- A model instance
- A string
- A QuerySet
Answer: A string. __str__ must always return a string.
How is a @property accessed on an instance?
- With parentheses, like post.word_count()
- Without parentheses, like post.word_count
- Only in the admin
- Via the manager
Answer: Without parentheses, like post.word_count. A @property reads like an attribute, without parentheses.
What does get_absolute_url return?
- The canonical URL of the object
- The page title
- The database id
- A list of URLs
Answer: The canonical URL of the object. get_absolute_url returns the object's canonical URL.
When overriding save(), what must you call so the row is written?
- self.write()
- self.commit()
- models.save()
- super().save(*args, **kwargs)
Answer: super().save(*args, **kwargs). You must call super().save() to actually persist the row.
What happens if you override save() but forget super().save()?
- The row is written twice
- Your logic runs but nothing is saved
- Django raises a syntax error
- The model is deleted
Answer: Your logic runs but nothing is saved. Without super().save(), the custom logic runs but no row is written.
Which class Meta option sets the default sort order?
- sort
- order_by
- ordering
- default_order
Answer: ordering. Meta.ordering sets the default sort, e.g. ['-created_at'].
What does ordering = ['-created_at'] mean?
- Ascending by created_at
- No ordering
- Sort by id
- Descending by created_at (newest first)
Answer: Descending by created_at (newest first). A leading minus means descending order, newest first.
Which Meta option fixes Django's naive pluralisation in the admin?
- plural_name
- name_plural
- verbose_name_plural
- verbose_plural
Answer: verbose_name_plural. verbose_name_plural overrides the auto-pluralised display name.