13. Database and Migrations#

  • Reference

  • Django’s ORM (Object-Relational Mapping) provides a powerful and flexible way to interact with databases.

  • This tutorial will guide you through setting up models, creating and applying migrations, and managing your database schema. We’ll use a blogging application with Post, User, and Comment models as examples.

13.1. Setting Up Your Models#

  • Let’s start by defining our models in blog/models.py.

  • Here is a table listing the supported field types in Django's django.db.models module along with examples for each

Field Type

Description

Example

CharField

A string field, for small- to large-sized strings.

name = models.CharField(max_length=100)

TextField

A large text field. Use this for large amounts of text.

description = models.TextField()

IntegerField

An integer field.

age = models.IntegerField()

FloatField

A floating-point number field.

price = models.FloatField()

BooleanField

A boolean field.

is_active = models.BooleanField(default=True)

DateField

A date field.

birth_date = models.DateField()

DateTimeField

A date and time field.

created_at = models.DateTimeField(auto_now_add=True)

TimeField

A time field.

start_time = models.TimeField()

EmailField

An Email field.

email = models.EmailField()

URLField

A URL field.

website = models.URLField()

SlugField

A slug field.

slug = models.SlugField()

FileField

A file upload field.

file = models.FileField(upload_to='uploads/')

ImageField

An image upload field.

image = models.ImageField(upload_to='images/')

ForeignKey

A many-to-one relationship.

author = models.ForeignKey(Author, on_delete=models.CASCADE)

OneToOneField

A one-to-one relationship.

profile = models.OneToOneField(Profile, on_delete=models.CASCADE)

ManyToManyField

A many-to-many relationship.

categories = models.ManyToManyField(Category)

DecimalField

A fixed-precision decimal number field.

price = models.DecimalField(max_digits=10, decimal_places=2)

PositiveIntegerField

An integer field for positive values only.

quantity = models.PositiveIntegerField()

PositiveSmallIntegerField

A small integer field for positive values only.

rank = models.PositiveSmallIntegerField()

SmallIntegerField

A small integer field.

votes = models.SmallIntegerField()

DurationField

A field for storing periods of time.

duration = models.DurationField()

UUIDField

A field for storing universally unique identifiers.

uuid = models.UUIDField(default=uuid.uuid4, editable=False)

BinaryField

A field for storing binary data.

data = models.BinaryField()

JSONField

A field for storing JSON data.

metadata = models.JSONField()

13.1.1. Post Model#

  • CharField: Represents a short-to-mid-sized string.

  • ForeignKey: Creates a many-to-one relationship to the User model.

  • TextField: Represents large text fields.

  • DateTimeField: Represents a date and time field, with default set to the current time.

    from django.db import models
    from django.utils import timezone
    from django.contrib.auth.models import User
    
    class Post(models.Model):
        title = models.CharField(max_length=80)
        author = models.ForeignKey(User, on_delete=models.CASCADE)
        content = models.TextField()
        date_posted = models.DateTimeField(default=timezone.now)
    
        def __str__(self):
            return self.title
    
    

13.1.2. Comment Model#

  • ForeignKey to Post and User: Each comment is associated with a specific post and user.

    class Comment(models.Model):
        post = models.ForeignKey(Post, on_delete=models.CASCADE)
        author = models.ForeignKey(User, on_delete=models.CASCADE)
        content = models.TextField()
        date_posted = models.DateTimeField(default=timezone.now)
    
        def __str__(self):
            return f'Comment by {self.author} on {self.post}'
    

13.2. Creating and Applying Migrations#

  • After defining your models, you need to create and apply migrations to update the database schema.

13.2.1. Creating Migrations#

  • Run the following command to create migrations based on the changes in your models

  • This command generates a migration file in the blog/migrations directory.

    python manage.py makemigrations
    

13.2.2. Applying Migrations#

  • To apply the migrations and update the database schema, run:

  • This command applies the migrations to your database, creating the necessary tables and fields.

    python manage.py migrate
    

13.3. Creating Demo Data#

  • First, ensure you have access to Django’s shell to execute Python code within the context of your Django project. Run the following command:

    python manage.py shell
    
  • Within the shell, you can create instances of your models.

    from django.contrib.auth.models import User
    from blog.models import Post, Comment
    from django.utils import timezone
    
    # Create a user
    user = User.objects.create_user(username='john_doe', email='john@example.com', password='password123')
    
    # Create some posts
    post1 = Post.objects.create(title='First Post', author=user, content='This is the content of the first post', date_posted=timezone.now())
    post2 = Post.objects.create(title='Second Post', author=user, content='This is the content of the second post', date_posted=timezone.now())
    
    # Create comments for post1
    comment1 = Comment.objects.create(post=post1, author=user, content='This is the first comment on the first post', date_posted=timezone.now())
    comment2 = Comment.objects.create(post=post1, author=user, content='This is the second comment on the first post', date_posted=timezone.now())
    
    # Create a comment for post2
    comment3 = Comment.objects.create(post=post2, author=user, content='This is the first comment on the second post', date_posted=timezone.now())
    
  • If you facing any problem, you can re-create database, but your all data will be gone (including super-user)

    • In default, Django use db.sqlite3 to store all data

      rm db.sqlite3
      

13.4. ORM Queries#

13.4.1. Basic Queries#

  1. Retrieve all posts

  2. Filter posts by author

  3. Get a single post by ID

    # Retrieve all posts
    all_posts = Post.objects.all()
    # Filter posts by author
    author_posts = Post.objects.filter(author=user)
    # Get a single post by ID
    single_post = Post.objects.get(id=1)
    

13.4.3. Advanced Queries [field lookups]#

  • Django’s ORM uses field lookups, which are used to create complex queries.

  • Here’s a table of common field lookups with their purpose and examples:

Function

Purpose

Example

exact

Exact match

Post.objects.filter(title__exact='First Post')

iexact

Case-insensitive exact match

Post.objects.filter(title__iexact='first post')

contains

Contains substring

Post.objects.filter(content__contains='Django')

icontains

Case-insensitive contains

Post.objects.filter(content__icontains='django')

in

Value is in a given list

Post.objects.filter(id__in=[1, 2, 3])

gt

Greater than

Post.objects.filter(date_posted__gt=timezone.now() - timedelta(days=7))

gte

Greater than or equal to

Post.objects.filter(date_posted__gte=timezone.now() - timedelta(days=7))

lt

Less than

Post.objects.filter(date_posted__lt=timezone.now())

lte

Less than or equal to

Post.objects.filter(date_posted__lte=timezone.now())

startswith

Starts with substring

Post.objects.filter(title__startswith='Fir')

istartswith

Case-insensitive starts with substring

Post.objects.filter(title__istartswith='fir')

endswith

Ends with substring

Post.objects.filter(title__endswith='Post')

iendswith

Case-insensitive ends with substring

Post.objects.filter(title__iendswith='post')

range

Value is within a range

Post.objects.filter(date_posted__range=[start_date, end_date])

date

Match a specific date

Post.objects.filter(date_posted__date=datetime.date(2023, 6, 17))

year

Match a specific year

Post.objects.filter(date_posted__year=2023)

month

Match a specific month

Post.objects.filter(date_posted__month=6)

day

Match a specific day

Post.objects.filter(date_posted__day=17)

week_day

Match a specific day of the week

Post.objects.filter(date_posted__week_day=2)

isnull

Check for NULL (or not NULL)

Post.objects.filter(author__isnull=True)

  1. Retrieve posts containing a keyword

  2. Retrieve posts published in the last 7 days

  3. Order posts by date posted (newest first)

    # Retrieve posts containing a keyword
    keyword_posts = Post.objects.filter(content__icontains='content')
    # Retrieve posts published in the last 7 days
    recent_posts = Post.objects.filter(date_posted__gte=timezone.now() - timezone.timedelta(days=7))
    # Order posts by date posted (newest first)
    ordered_posts = Post.objects.all().order_by('-date_posted')
    

13.5. Working with the Admin Interface#

  • Register your models with the admin interface to manage them through Django’s admin panel.

13.5.1. Registering Models#

  • In blog/admin.py, register your models:

  • This will make the Post and Comment models accessible in the admin interface.

    from django.contrib import admin
    from .models import Post, Comment
    
    admin.site.register(Post)
    admin.site.register(Comment)