Models in Django: what they are, how to create them and use them step by step

Video thumbnail

When I started with Django, what surprised me the most was its way of managing the database through models. If you come from PHP, as I did, and you've worked with frameworks like Laravel or CodeIgniter, you'll notice a huge difference: in Django, you can centralize the entire definition of your tables in a single file and maintain clean control over your data structure.

In this article, I'll tell you what models in Django are, how they are created step-by-step, and how to leverage them to structure your database professionally.

We start from how to display a Hello World in Django.

What is a model in Django and why is it so important

A model is one of the most powerful layers of the MTV (Model–Template–View) pattern.
It represents the structure and behavior of the data your application works with. In simple terms, each model is equivalent to a database table and each class attribute is a column.

In Django, the model is your "window" to the database: it defines how data is stored, how it relates, and how you can query it using the ORM (Object Relational Mapper) without writing a single line of SQL.

The Model as part of the MTV pattern

The model is the "M" in MTV. It is responsible for:

  • Structuring data (fields and types).
  • Managing relationships between entities.
  • Controlling business logic (through methods).

How Django converts a class into a table

When you define a class in models.py and run a migration, Django automatically generates the corresponding table in your database. This process is the heart of the ORM.

Models and the application's single file in Django

To create a model, we obviously need to have a Django project and application, which we already did previously, in the application called:

firstProject

We have a file called models.py which is completely empty; as you can deduce from the file name, it serves to store or define ALL the models for this application, therefore if you come from PHP like me, this might be a bit shocking since in popular frameworks like CodeIgniter or Laravel, we define one model per class, meaning, in one model we only have one class stored and that's it; but in Django, specifically in Python, this is not the case and this is very good.

A huge advantage we have when creating classes as models or forms in Django is that we can define all the structures, that is, the classes, in a single file, therefore we can have great control over each of the layers or sublayers of our project.

And this is due to the great modularization and organization when importing a class, function, or variable from Python.

How to create a model in Django

Finally, we are going to create a model; a model is simply a Python class that defines attributes where each attribute is generally a field of our object which will later translate as a column in the database, but we will get to that.

Field types

We have multiple field types that we can use, for text, numbers, boolean files, images, and a long etc:

You can see more in the official documentation

So, finally we are going to create a model, for example, one we created in our great course on Django that looks like this:

class Comment(models.Model):
    text = models.TextField()
    date_posted = models.DateTimeField(auto_now_add=True)
    element = models.ForeignKey(Element, related_name='comments', on_delete=models.CASCADE, NULL=True)
 
    def __str__(self):
        return 'Comentario #{}'.format(self.id)

Explanation of the code above

So, we have a property for the comment text and a date, it's that simple; but as you can see, we can also define attributes on the fields, and depending on the field type we can define certain attributes or options, as is the case for auto_now_add which receives a boolean to indicate that as soon as we create this record in the database, it should take the system's current date.

As you can see, we simply have to specify the field type with the corresponding function, for example TextField for an open text field, or a DateTimeField field for a date field, we specify the name of the column which would be the same name as the attribute, and that's it.

And with this we create our first model in Django; in the next posts we will see what else we can do with this new element in Django.

We also specified the type of relationship, which in this case is cascade.

Models are the single, definitive source of information about your data. It contains the essential fields and behaviors of the data you are storing (the business logic). Generally, each model maps to a single database table and is one of the layers of our MTV.

And, ultimately, they are the layer that allows access to the database and is the only entry to it; each application in Django can have zero or more models, all of which live within the file called models.py which is defined in each application.

A model is nothing more than a class, where said class will be reflected in the database to a table; that is, a model class (meaning a class that is defined within the models.py file) will correspond to a table in the database.

It is important to point out that, to create the corresponding tables in the database, it is necessary to execute a command, but we will see that later.

Creating Models

Models are part of the applications in Django; inside the file called models.py just as its name indicates, we can define all the models that will be used in the application or other applications through imports.

You can verify the latter in the description of the models.py file

# Models here

Practical Case

Inside the application we created earlier, we are going to create the following classes:

elements/models.py

from django.db import models
# Create your models here.
class Category(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255)
    def __str__(self):
        return self.title
class Type(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255)
    def __str__(self):
        return self.title
class Element(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255,blank=True)
    description = models.TextField()
    price = models.DecimalField(max_digits=10,decimal_places=2, default=6.10) # 12345678.10
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)
    type = models.ForeignKey(Type, on_delete=models.CASCADE)

Explanation of the code above

In one of my projects, I used three main models: Category, Type, and Element.

Each one represents an entity in the system, and their structure allows for easy scaling.

Here you can already start to see the wonders of Python; clean, expressive syntax and you probably already understand to a good extent what we are defining.

The first thing we do is import the Model class from Django:

from django.db import models
*
models.Model

Then, we create classes that inherit from the previous import:

class Category(models.Model):
   *
class Type(models.Model):
   *
class Element(models.Model):
   *

Endowing these classes with certain characteristics that we will see little by little, which in this very particular case would be to manage the models, including connections to the database and mapping of said classes to the database through migrations.

Then, each of the previous properties defined in said class, make up the structure of the entity we want to create; in this case categories, types, and elements.

Here in this elements/models.py file, we created three different models, two of which are simple and are for the category and the type, and the third is a bit more elaborate, whose intention is to be able to register posts; posts that can be a blog post, course, or any other classification you want to use; the term "element" is used in the book to place a neutral name for each of these types or classifications.

Let's break down the Element class; by understanding its columns, you will understand those of the other two classes and similar definitions:

  • With models.CharField(max_length=255) for the title property, we define a text type field (CharField) which allows storing characters, with an attribute to limit the maximum size to 255 characters (max_length).
  • With models.SlugField(max_length=255,blank=True) for the slug property, we define a SlugField type field, which allows storing only letters, numbers, and hyphens, which is ideal for managing clean URLs or slugs.
    • With blank we indicate that it can store blank values.
  • With models.DecimalField(max_digits=10,decimal_places=2, default=6.10) for the price property, we indicate a decimal type field with a maximum length of 10 digits and two decimal places with a default value of 6.10.
  • With models.ForeignKey(, on_delete=models.CASCADE)** We will create a cascade-type foreign relationship, with the category and type.
  • For models.TextField() for the description property, we define a text type field; this is ideal for storing large amounts of text.
  • For the date fields for created and updated which represent the creation and update dates of records respectively, we indicate the DateTimeField type field, which with the auto_now_add attribute we indicate that it should set a date when the object is generated, and with auto_now we indicate that when saving the object, it should set the current date.

The reason for this structure is due to any type of real-world post; if you want to create a post, the basic elements are a title and content; generally, we indicate a summary or description, and of course, control dates are always welcome; finally, having many posts of various types, we add classifications as we indicated previously.

In the end, it is important that you familiarize yourself with the column types and attributes to use those that best suit your needs:

https://docs.djangoproject.com/en/dev/ref/models/fields/#field-types

Migrations: reflecting your models in the database

Once the models are defined, the next step is to create the tables in the database.

$ python manage.py makemigrations
$ python manage.py migrate

These commands generate and apply the necessary scripts.

On one occasion I forgot to run makemigrations before modifying a model, and I ended up with synchronization errors. Since then, I always version control my migrations.

Tip: avoid deleting fields directly without migrating first; you could lose valuable data.

How to register and test your models in the administration panel

Django facilitates data management thanks to its admin panel.
You just need to register your models in admin.py:

from django.contrib import admin
from .models import Category, Type, Element
admin.site.register(Category)
admin.site.register(Type)
admin.site.register(Element)

When you access /admin, you will see your models ready to create, edit, or delete records from a graphical interface.

⚠️ Common errors and best practices

  • Forgetting null=True in optional relationships.
  • Not defining __str__(): without this method, your records will look like generic objects.
  • Modifying fields without generating prior migrations.

In my experience, it's best to keep the models simple at the beginning and refactor when the project structure is clear. Django is very flexible with changes if you migrate correctly.

If you come from frameworks like Laravel, you will love seeing how Django simplifies schema management without breaking compatibility.

The __str__ method on models to print a text representation of the model/class

The next thing we are going to see is a feature that allows us to represent an object as a String and that is the method called Str.

Since if we try to print from a template or using the print function an object that belongs to a model (or class in general); we will see that something like the following will appear:

Comment object (1)

Where the Comment is the name of the model and the (1) is the identifier in the database.

Now, we can represent a Django model as if it were a simple text; This is really a feature that Python offers us and not Django, which is being able to represent an object as if it were a string; therefore, when we print this object, basically the representation that we define in the Str function will appear; for example, for our model:

class Comment(models.Model):
    text = models.TextField()
    date_posted = models.DateTimeField(auto_now_add=True)
    element = models.ForeignKey(Element, related_name='comments', on_delete=models.CASCADE, NULL=True)
 
    def __str__(self):
        return 'Comentario #{}'.format(self.id) 

Here we can access all the attributes and methods of the model that contains said function; and this method is used internally by Python to represent said instance of a class by means of a string when printing the text.

And if we print the following object:

print(elements[0])

When making a print:

Comentario #1

The text we set earlier will appear; you can use this for A whenever you have a class and at some point you want to print it, either through the print function or from the Django template.

Conclusion: why models are the heart of Django

Models are the foundation of every Django project.
They allow you to manage data, relationships, and business logic without worrying about SQL. Furthermore, Django's ORM translates your classes into efficient and secure queries.

When I understood this, I stopped thinking of Django as just another framework and started seeing it as a complete tool for structured development.

❓ Frequently Asked Questions (FAQ)

1. What is the difference between a model and a migration?
The model defines the structure in Python; the migration creates or modifies the table in the database.

2. How to relate models to each other?
Using fields like ForeignKey, OneToOneField, or ManyToManyField.

3. Where is the models.py file defined?
In each Django application, inside its main folder.

4. What command is used to apply migrations?
python manage.py migrate

The next step is to learn how you can change the database to MySQL.

I agree to receive announcements of interest about this Blog.

We are going to see how we can create a model in Django, which remember is one of the MTV layers of our application and the one in charge of managing its data; we will also see how to define different fields.

| 👤 Andrés Cruz

🇪🇸 En español