Django Tutorial Part 4: Creating Models

Disclaimer: Your support helps keep JovialGuide running! Our content is reader-supported. This means if you click on some of our links, we may earn a commission.

In part 1 of this complete beginners guide to Django: introduction to Django, we introduced you to Django, popular sites using Django and what can Django do, in part 2, we showed you how to install Django in a virtual environment and in part 3, we showed you Part 3: how to create an hello world site.

Django comes with models which is a layer to create your database tables. In this complete beginners guide to Django part 4, we will show you how to create Django models. This is a complete beginners guide to Django, so if you haven’t read the previous part (part 3), then see Part 3: how to create an hello, world! site or see part 1 – introduction to Django to get started.

Migrating the Default Django Configuration Tables

Earlier in part 3 we noticed that Django warned us about unapplied migrations. If you look at the command line, you will still see the message, which says:

You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.    
Run 'python manage.py migrate' to apply them.
  • It is a warning so, it is not that serious. However, now that we want to start working with the database by creating models, then we need to attend to this warning!
  • Basically, this message means that there are some project configuration tables Django uses, such as: admin, auth, contenttypes, and sessions. And without them, our Django project may not work well. This warning requires us to run the migrate command for Django to create the default configuration tables it will need to communicate well with our project. Looking at the warning, you will notice that it is showing us the command to use.

To migrate the default Django project configuration tables, run the following command:

python manage.py migrate

The output on the command line should look like this:

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK
  • What the migrate command does is to create the tables that will be needed to work well with your Django project.

If you start your development server using the following command, then you will not see the warning again:

python manage.py runserver

What is a Django Model?

To create a dynamic website (one that interacts with a database), one will have to learn SQL which stands for Structured Query Language, used for Creating, Reading, Updating and Deleting data (CRUD operation) in a table. Learning and mastering SQL requires a lot of time invested, because it comes with several complicated statements for each operation one would want to perform. Django solves this hassle by introducing the concept of models. Django models solve this problem by organizing models into tables, and mapping them into a database without writing any SQL query.

A model is an entity which is automatically turned into a database table. It is basically your database layout which is used to automatically generate database tables for your Django app. Django allows you to define models (database tables) in the models.py file of your Django app. Django uses models to create tables, database constraints and fields.

Creating a Model in Django (Syntax)

Django models are defined in the models.py file of your Django app. A typical Django model looks like this:

from django.db import models
from django.urls import reverse

class ModelName(models.Model):
  field_name = models.CharField(max_length=30)
  another_field_name = models.TextField()

  # Methods
  def get_absolute_url(self):
    return reverse('detail-view', args=[str(self.id)])

  def __str__(self):
    return self.field_name
  • The first line imports models from django.db, and reverse from django.urls. The reverse function will be used to return the reverse form of a URL from a view that is mapped to a URL
  • The ModelName model is a database table, and subclasses the django.db.models class. The django.db.models class provides Django with a lot of information, and allows Django to create a database layout or schema using the CREATE TABLE statement in SQL. The ModelName is basically a database table
  • field_name and another_field_name are to be replaced with the name you want to call your fields. They are attributes, which basically represent database fields. field_name uses CharField(), which is similar to the HTML input element, while another_field_name uses TextField(), which is similar to the HTML textarea element. Each of the fields is mapped to the ModelName model, which is a database table
  • Django model fields accept arguments that allow you to specify additional information for the field. Information like: max_length – for specifying the maximum number of characters such field can hold, etc. (More on this in a bit!)

Django Model Methods

  • You can define methods to use, inside of Django models. In our example, we defined the get_absolute_url() model method which returns a full form of your URL
  • The __str__ method is a magic (or dunder) method in Python. It returns the string representation that will be used to display the ModelName model objects in the Django admin site
  • In a standard Django model, you should always define the __str__ method. The __str__ method returns the human-readable string representation for each object of a model

When working with Django models, note that:

  • Each model is a Python class that subclasses django.db.models
  • Each model maps to a single database table
  • Each attribute in a model basically represents a database field.

Notice we didn’t add an id field to the model. This is because Django automatically creates it for us.

Creating the Blog Model

For this complete beginners guide to Django we will create a blog in Django. So, in this section, we will define the blog model that will be used for this tutorial series. Open the models.py file in your blog app. You will see:

from django.db import models

# Create your models here.

Update it by adding two more imports on the next line, like below:

from django.urls import reverse
from django.contrib.auth.models import User

Creating The Category Model

The Category model is a database table that will store the categories each blog post belongs to. Copy and paste in your blog’s models.py file after the imports:

class Category(models.Model):

  title = models.CharField(max_length=200)
  description = models.TextField()
  created_at = models.DateTimeField(auto_now_add=True)
  updated_at = models.DateTimeField(auto_now=True)

  def get_absolute_url(self):
    return reverse('category-detail', args=[str(self.id)])

  def get_edit_url(self):
    return reverse('category-edit', args=[str(self.id)])
    
  def get_delete_url(self):
    return reverse('category-delete', args=[str(self.id)])


  def __str__(self):
    return self.title
  • title – This field will hold each category title. It has CharField() as the field type with a max_length of 200. The max_length argument or field option is required for a CharField().
  • description – This field will hold the description of each category. It has the TextField() field, which is similar to the HTML textarea element.
  • created_at – The created_at field has a DateTimeField() field, which will store the date and time each category was created. It has auto_now_add=True, meaning that the current date and time will be used on this field when a category is created.
  • updated_at – This field will store the date and time the category was edited or updated. It has a DateTimeField() field, and auto_now=True field option, which means that each time a category is updated, this field will be updated with the current timestamp.
  • After that, we created a get_absolute_url() and returned a reverse (we imported), with category-detail as the view name and self.id as the args (arguments). self.id points to the id field in the category model which Django automatically creates for us. The id field is unique!
  • The get_edit_url() and the get_delete_url() model methods will return the full URL for editing and deleting categories.
  • Next we defined the string (__str__() method) representation of the object in the Category model. We returned self.title which is the title field of the Category model.

Creating The Article Model

The Article model is a database table that will store articles or blog posts. Copy and paste in your blog’s models.py file.

class Article(models.Model):

  STATUS_CHOICES = [
    ('unpublished', 'Unpublished'),
    ('published', 'Published')
  ]

  author = models.ForeignKey(User, on_delete=models.CASCADE)
  title = models.CharField(max_length=200)
  content = models.TextField()
  featured_img = models.ImageField(upload_to='uploads/%Y/%m/', verbose_name='Featured Image')
  status = models.CharField(max_length=50, choices=STATUS_CHOICES, default='unpublished')
  category = models.ForeignKey(Category, on_delete=models.CASCADE)
  created_at = models.DateTimeField(auto_now_add=True)
  updated_at = models.DateTimeField(auto_now=True)

  def get_absolute_url(self):
    return reverse('article-detail', args=[str(self.id)])

  def get_edit_url(self):
    return reverse('article-edit', args=[str(self.id)])
    
  def get_delete_url(self):
    return reverse('article-delete', args=[str(self.id)])

  def __str__(self):
    return self.title
  • author – The author field will store the author of each article. It has a ForeignKey relationship pointing to the built-in Django User model (we imported earlier), and on_delete=models.CASCADE, which means delete every article that belongs to this user when the user account is deleted
  • title – This field will hold each article title. It has CharField() with a max_length of 200. The max_length argument or field option is required for a CharField().
  • content – This field will hold the content or body of each article. It has the TextField() field, which is similar to the HTML textarea element.
  • featured_img – This is an ImageField field. It has an upload_to field option which is used for specifying where the images are to be uploaded to. The value of the upload_to is uploads/%Y/%m/uploads folder » Y = year folder » M = month folder. This basically means that for each file we upload, it creates a folder called uploads, inside, it creates another folder with the current year, inside the year folder, it creates another folder with the current month of the year. Then put the uploaded file inside the month folder. Basically, if we have upload_to=’uploads/%Y/%m/’ and we upload a file named jovialguide-logo.png and today’s date is 2022/01/20 – YYYY-MM-DD, then the file will be uploaded to uploads/2022/01/jovialguide-logo.png. Imagine if today’s date were to be 2021/11/03 – YYYY-MM-DD, then it would be uploaded to uploads/2021/11/jovialguide-logo.png. This is similar to the WordPress file upload system, because it creates a folder for each year and month for file uploads. This file upload system allows you organize your uploaded files into month and year!
  • The featured_img field also has a field option of verbose_name=’Featured Image’, which is the human-readable name for a field. If this is not specified, Django will use the field name, and if there is any underscore in the field name, then it will be converted to spaces. This means that if we do not specify the verbose_name for the featured_img field, then Django will display this field as featured img (converts underscores to spaces). However, now that we have verbose_name=’Featured Image’ on the featured_img field, then Django will display this field as Featured Image. This is the reason it is called the human-readable name for a field!
  • status – The status field has STATUS_CHOICES which is a list of tuples. It is defined inside of the Article model, right before the fields. The status field uses CharField as its field type and choices=STATUS_CHOICES (the STATUS_CHOICES that was defined earlier). This is used to create a select option (HTML option element) using defined values like we have above – Unpublished and Published. The values in small letters will be used on the backend to perform the checks, or to retrieve data, while the values in capital will only be used for display, just like verbose_name field option. Finally, we have default=’unpublished’ which means that ‘unpublished’ is the default selected value. This means that each time we create a new article and leave this field untouched, then the status will be set to ‘unpublished’. The reason for the choices field option is to allow us set some articles to published, while some to unpublished.
  • category – The category field will store the category each article belong to. It has a ForeignKey relationship, which points to the Category model we defined earlier, and on_delete=models.CASCADE, which means delete every article that belongs to this category when this category is deleted
  • created_at – The created_at field has a DateTimeField() field, which will store the date and time each article was created. It has auto_now_add=True, meaning that the current date and time will be used on this field when an article is created.
  • updated_at – This field will store the current timestamp the article was edited or updated. It has a DateTimeField() field, and auto_now=True field option, which means that each time an article is updated, this field will be updated with the current date and time.
  • We created a get_absolute_url() method and returned a reverse (we imported), with article-detail as the URL name and self.id as the args (arguments). self.id points to the id field in the article model which Django automatically creates for us.
  • The get_edit_url() and the get_delete_url() model methods will return the full URL for editing and deleting articles.
  • Lastly, we defined the string (__str__() method) representation of the object in the Article model. We returned self.title which is the title field of the Article model.

Creating Migrations from Models

If the development server is still running, press ctrl + c to stop it. Run the following command to create migrations for Category and Article models:

python manage.py makemigrations
  • The makemigrations command creates migration for the changes made in the Django models.py file. Migrations are created from Django models and are basically a history that Django can roll back to, to update the database layout or schema to match the current changes made in the models.py file

The following should be the result in the terminal or command prompt:

Migrations for 'blog':
  blog\migrations\0001_initial.py
    - Create model Category
    - Create model Article
  • Since this is the first makemigrations command that we have run, the command created a 0001_initial.py migration file with the name 0001_initial which means that this is the first or initial migration that has been made.

Migrating the Models

After running the makemigrations command, it creates a migration file for the changes you have made, but it doesn’t apply the actual changes that you have made in the models.py file. The changes in the models.py file have been recorded in the migration file that was auto-generated by the makemigrations command. To apply the actual changes, run the following command to make the actual changes to the database:

python manage.py migrate
  • The migrate command applies the actual changes from the migration file to the database.

The following should be the result in the terminal or command prompt:

Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK

Since this is the initial/first migrate command, it creates all of the required tables you need to work with Django.

Django Fields

Earlier we looked at CharField(), TextField(), etc., as some Django supported fields. There are many other field types in Django. The following are the supported field types in Django:

  • AutoField – This is an auto-increment integer field.
  • CharField – This is a character field, it accepts a max_length argument, which specifies the length of characters it can hold. You can see the CharField() field as the equivalent of the HTML input element.
  • DateField – This field is responsible for storing dates.
  • EmailField – This is similar to the CharField(), except that it accepts Emails alone, that is; it checks if the Email you enter is a valid Email address.
  • FileField – The FileField() allows you store media content references.
  • ImageField – This is a reserved field for storing images only.
  • IntegerField – This is a number field that is reserved for whole numbers alone.
  • SlugField – This is a CharField() field that allows you store slugs. If you are storing a slug/permalink, then you need the SlugField field.
  • TextField – The TextField() is a large text field for storing large volume of text like blog posts, product descriptions, etc. It is similar to the CharField(), except that it can hold large volume of words, characters or text. You can see the TextField() as the textarea element.
  • TimeField – This field is responsible for storing time.

Django Relationship Fields

Django model also allow you specify relationships between models. The following are the supported relationship types in Django:

  • OneToOneField – Any field in the Django model that has a OneToOneField relationship means that it can hold only unique data (no duplicates) in that field. This means that one item can have only one other item that is related in a table, and it must be unique throughout the OneToOneField field/column. OneToOneField field is like passing Unique=True argument to a field. This enforces uniqueness in such field.
  • ForeignKey – A ForeignKey or many-to-one (also called one-to-many) relationship is similar to the OneToOneField relationship, except that it can hold duplicate data compare to the OneToOneField relationship. This type of relationship means that one item can have many other related items in a table (duplicates inclusive).
  • ManyToManyField – The many-to-many relationship is like the many-to-one or ForeignKey relationship, except that a car can have several car models, and each car model can have several cars. This type of relationship is independent compare to ForeignKey and OneToOneField relationship.

Django Field Options

Django field options or field arguments allow you pass extra behavior to a field. The following are the field options in Django:

  • blank – This means that this field can be left blank. It accepts a boolean value of True or False. If you are passing blank=True, then it is recommended you also pass null=True to the same field.
  • null – This field can store null values (empty) in a field. It accepts a boolean value of True or False. If you are passing null=True, it is recommended you also pass blank=True to the same field.
  • default – This field argument allows you give your field a default value, and is used when no value or data is inputted. default=’This is a demo text when nothing is typed into the field’.
  • editable – This allows you specify if or not the field should be editable. It accepts a boolean value of True or False. By default, the updated_at = models.DateTimeField(auto_now=True) field has editable=False, which makes it impossible to edit.
  • help_text – The help_text field option allows you specify a guide or hint text on what the field is all about. help_text=’Please use CAPITAL LETTERS’.
  • max_length – The max_length Django field option is needed when using the CharField() field. Since CharField() is like the input element, it requires a text limit.
  • verbose_name – This is the human-readable name for a field. If this is not specified, Django will use the field name, and if there is any underscore in the field name, then it will be converted to spaces.
  • unique – This specifies if this field should be unique. It accepts a boolean value of True or False. If unique=True then this field will be unique throughout the table, and no duplicates will be stored.

Django Tutorial Series

In this Django tutorial series, we have been able to cover part 1 – part 3. If you need to read them again, please see:

In the next complete beginners guide to Django, we will show you:

We hope this complete beginners guide to Django – creating and working with Django models (part 4) helped you learn how to create a Django model, relationship fields, field options, etc. This is a complete beginners guide to Django, so if you haven’t read the previous part (part 3), then see Part 3: how to create an hello, world! site or see part 1 – introduction to Django to get started.

See other of our Django tutorials for more.

You Might Also Like

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Shares