Database and Models

In this article, we will create a model, set up the database, and implement immigration.

Doing so allows us to create our database instead of relying on dummy data!

Models

What is a model?

A model is a database layout containing the essential fields and behaviors of the data you’re storing.

Each model is represented by a class that subclasses django.db.models.Model.

Model field

Each model has class variables and a database field.

  1. CharField is a character field. It requires CharField.max_length.

  2. TextField is a large text field.

  3. DateTimeField presents the date and time.

  • DateTimeField(auto_now=True) will automatically set the day to current datetime every time the object is saved. It’s good if we set for the last_modified_date
  • DateField(auto_now_add=True) will automatically set the day to the current datetime when the object is first created. You can’t update the date posted.
  • To change the date, we can import from django.utils import timezone and add models.DateTimeField(default=timezone.now).
  1. EmailField checks that the value is a valid email address using EmailValidator. The max length is 254.

  2. ForeignKey shows relationships. It requires two arguments: the class to which the model is related and the on_delete option.

For example: author = models.ForeignKey(User, on_delete=models.CASCADE) will delete Post if User is delete.

Learning resources: You can check all Django Model Fields.

3-step guide to making model changes:

  • Change your models in models.py
  • Run python manage.py makemigrations to create migrations for those changes
  • Run python manage.py migrate to apply those changes to the database.

Example For example, we need Users(authors) and Posts for the blog app.

Because Django already has a built-in authentication system with a User model (admin page), so we just need to create a Post model.

Step 1: Change the models (in models.py)

Django already created a model.py file in the blog app, so we can open blog/models.py and edit:

from django.db import models
from django.utils import timezone # Import timezone for DateTimeField
from django.contrib.auth.models import User # Import User model

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    date = models.DateTimeField(default=timezone.now)
    author = models.ForeignKey(User, on_delete=models.CASCADE) # If a user created the post is deleted, posts are deleted as well.ß

    # __str__() method returns how the Post is printed
    def __str__(self):
        return self.title

Step 2: create migrations for those changes

After making changes to the Django database, we need to run makemigrations to create new migrations based on the detected modifications to your models.

$ python manage.py makemigrations
Migrations for 'blog':
  blog/migrations/0001_initial.py
    - Create model Post

Here, we have 0001_initial.py in the migration directory in our blog app.

Note: Check SQL code

We can check the exact SQL code that will be generated with the code python manage.py sqlmigrate APP_NAME MIGRATION_NUMBER.

python manage.py sqlmigrate blog 0001

We’ll see this

BEGIN;
--
-- Create model Post
--
CREATE TABLE "blog_post" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "title" varchar(100) NOT NULL, "content" text NOT NULL, "date" datetime NOT NULL, "author_id" integer NOT NULL REFERENCES "auth_user" ("id") DEFERRABLE INITIALLY DEFERRED);
CREATE INDEX "blog_post_author_id_dd7a8485" ON "blog_post" ("author_id");
COMMIT;

Step 3: Apply those changes to the database

Run migrate command to create those model tables in our database:

$ python manage.py migrate

Migrations are very useful because they let us change models over time even after it is created and has data in the database.

The migrate command takes all the migrations that haven’t been applied.

Interact with API

Once you’ve created your data models, Django automatically provides a database-abstraction API that lets you create, retrieve, update and delete objects.

  1. To invoke the Python shell, use this command:
$ python manage.py shell
  1. To import the Post model and User model.
>>> from blog.models import Post
>>> from django.contrib.auth.models import User
  1. To check all the Users
>>> User.objects.all()
  1. To check the first User
>>> User.objects.all().first()
  1. We can filter the result by using filter() method. In this code, we add the first() method to take the first result, and store the value in the uservariable.
>>> user = User.objects.filter(username='filter-value').first()

We can check:

  • user id: user.id
  • user email: user.email
  1. To check if we have any Post
>>> Post.objects.all()
<QuerySet [>]>

Because we haven’t created any posts, it shows an empty list.

  1. To add post
>>> post_1 = Post(title='Blog 1', content='First post content', author=user)
  1. To save post:
>>> post_1.save()

Querry our Post again, we’ll see:

>>> Post.objects.all()
<QuerySet [<Post: Blog 1>]>

We can create a second post with step 7 and 8.

  1. To access the fields of first post.
>>> post = Post.objects.first()
>>> post.content
'First post content'
>>> post.date
datetime.datetime(2020, 8, 10, 15, 29, 4, 220800, tzinfo=<UTC>)
>>> post.title
'Blog 1'
  1. To check all the posts created by the user:
>>> user.post_set.all()
<QuerySet [<Post: Blog 1>, <Post: Blog 2>]>
  1. To create a post directly using post_set:
>>> user.post_set.create(title='Blog 3', content='Third post content')
<Post: Blog 3>

We don’t need to run .save() in this case because it’s automatically saved.

If we run our Post.objects.all() again, we’ll see:

<QuerySet [<Post: Blog 1>, <Post: Blog 2>, <Post: Blog 3>]>

Apply Database to blog app

After adding the database using the Python shell, we can add posts to our blog app.

  • Open our blog/views.py
  • Import our Post model: from .models import Post.
  • Update the context part:
    context = {
        'posts': Post.objects.all() # Get the posts from the Post Database
    }

So here is our final code:

from django.shortcuts import render
from .models import Post

def index(request):
    context = {
        'posts': Post.objects.all()
    }
    return render(request, 'blog/index.html', context)

def about(request):
    return render(request, 'blog/about.html', {'title': 'About'})