Creating a blog model in django
A Django model is a source of information and behaviors of your data. It consists of a Python class that subclasses django.db.models.Model. Each model maps to a single database table, where each attribute of the class represents a database field.
Creating the Post model
from django.db import models
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def__str__(self):
return self.title
Defining a default sort order
Blog posts are usually displayed in reverse chronological order (from newest to oldest). We will define a default ordering for our model. The default order will apply when obtaining objects from the database when no order is specified in the query.
from django.db import models
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-publish']
def__str__(self):
return self.title
We have added a Meta class inside the model. This class defines metadata for the model. We use the ordering attribute to tell Django that it should sort results by the publish field. This ordering will apply by default for database queries when no specific order is provided in the query. We indicate descending order by using a hyphen before the field name, -publish. Posts will be returned in reverse chronological order by default.
Adding a database index
from django.db import models
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-publish']
indexes = [
models.Index(fields=['-publish']),
]
def__str__(self):
return self.title
Danger
Index ordering is not supported on MySQL. If you use MySQL for the database, a descending index will be created as a normal index.
Activating the application
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog.apps.BlogConfig',
]
The BlogConfig class is the application configuration. Now Django knows that the application is active for this project and will be able to load the application models.
Adding a status field
A common functionality for blogs is to save posts as a draft until ready for publication. We will add a status field to our model that will allow us to manage the status of blog posts. We will be using Draft and Published statuses for posts.
from django.db import models
from django.utils import timezone
class Post(models.Model):
class Status(models.TextChoices):
DRAFT = 'DF', 'Draft'
PUBLISHED = 'PB', 'Published'
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(
max_length=2,
choices=Status.choices,
default=Status.DRAFT
)
class Meta:
ordering = ['-publish']
indexes = [
models.Index(fields=['-publish']),
]
def__str__(self):
return self.title
We have defined the enumeration class Status by subclassing models.TextChoices . The available choices for the post status are DRAFT and PUBLISHED. Their respective values are DF and PB, and their labels or readable names are Draft and Published.
Django provides enumeration types that you can subclass to define choices simply. These are based on the enum object of Python’s standard library. You can read more about enum at https://docs.python.org/3/library/enum.html.
Shell
python manage.py shell
>>> from blog.models import Post
>>> Post.Status.choices
[('DF', 'Draft'), ('PB', 'Published')]
>>> Post.Status.labels
['Draft', 'Published']
>>> Post.Status.values
['DF', 'PB']
>>> Post.Status.names
['DRAFT', 'PUBLISHED']
You can access a specific lookup enumeration member with Post.Status.PUBLISHED and you can access its .name and .value properties as well.
Adding a many-to-one relationship
Posts are always written by an author. We will create a relationship between users and posts that will indicate which user wrote which posts. Django comes with an authentication framework that handles user accounts. The Django authentication framework comes in the django.contrib.auth package and contains a User model.
We will use the User model from the Django authentication framework to create a relationship between users and posts.
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class Post(models.Model):
class Status(models.TextChoices):
DRAFT = 'DF', 'Draft'
PUBLISHED = 'PB', 'Published'
title = models.CharField(max_length=250)
slug = models.SlugField(max_length=250)
author = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name='blog_posts'
)
body = models.TextField()
publish = models.DateTimeField(default=timezone.now)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
status = models.CharField(
max_length=2,
choices=Status.choices,
default=Status.DRAFT
)
class Meta:
ordering = ['-publish']
indexes = [
models.Index(fields=['-publish']),
]
def__str__(self):
return self.title