2023年Django模型创建完全指南:从入门到实例详解
引言在之前的教程《如何创建一个Django应用并连接到数据库》中,我们介绍了如何创建一个MySQL数据库,如何创建和启动一个Django应用,并如何将其连接到一个MySQL数据库。
在本教程中,我们将创建Django模型来定义我们将存储的博客应用程序数据的字段和行为。这些模型将数据从您的Django应用程序映射到数据库。它是Django使用的通过对象关系映射(ORM)API生成数据库表的方式,被称为“模型”。
先决条件这个教程是Django开发系列的一部分,也是这个系列的延续。
如果您还没有跟随本系列的进展,那我们做出以下假设:
- You have Django version 4 or higher installed.
- You have connected your Django app to a database. We are using MySQL, and you can achieve this connection by following part two of the Django series, “How To Create a Django App and Connect it to a Database.”
- You are working with a Unix-based operating system, preferably an Ubuntu 22.04 cloud server as this is the system we have tested on. If you would like to set up Django on a similar environment, please refer to our tutorial, “How To Install Django and Set Up a Development Environment on Ubuntu 22.04.”
由于本教程主要涉及Django模型,即使您的设置有些不同,您也可能能够跟随进行。
第一步 – 创建Django应用程序为了与Django的模块化理念保持一致,我们将在项目中创建一个Django应用程序,其中包含创建博客网站所需的所有文件。
每当我们开始在Python和Django中工作时,我们应该激活Python虚拟环境并进入我们应用的根目录。如果您跟随整个系列操作,可以通过输入以下命令来实现这一点。
- cd ~/my_blog_app
- . env/bin/activate
- cd blog
从那里开始,让我们运行这个命令。
- python manage.py startapp blogsite
这将创建我们的应用程序,并附带一个博客网址目录。
在本教程系列的这一点上,您将为您的项目拥有以下目录结构:
my_blog_app/
└── blog
├── blog
│ ├── __init__.py
│ ├── __pycache__
│ │ ├── __init__.cpython-38.pyc
│ │ ├── settings.cpython-38.pyc
│ │ ├── urls.cpython-38.pyc
│ │ └── wsgi.cpython-38.pyc
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── blogsite
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
└── manage.py
我们在本教程中要重点关注的文件是位于blogsite目录下的models.py文件。
第二步 – 添加文章模型 bù -首先,我们需要打开并编辑models.py文件,以便其中包含用于生成帖子模型的代码。帖子模型包含以下数据库字段:
- title — The title of the blog post.
- slug — Where valid URLs are stored and generated for web pages.
- content — The textual content of the blog post.
- created_on — The date on which the post was created.
- author — The person who has written the post.
现在,进入包含models.py文件的目录中。
- cd ~/my_blog_app/blog/blogsite
使用cat命令在终端中显示文件的内容。
- cat models.py
文件应该包含以下代码,其中包含导入模块的语句,并有一条注释描述该models.py文件中需要放置的内容。
from django.db import models
# Create your models here.
请使用你喜爱的文本编辑器,在models.py文件中添加以下代码。我们将使用nano作为我们的文本编辑器,但你可以使用任何你喜欢的。
- nano models.py
在这个文件中,已经添加了导入模型 API 的代码,我们可以继续删除后面的注释。然后,我们将导入 slugify 用于从字符串生成 slug,导入 Django 的 User 进行身份验证,并从 django.urls 导入 reverse,以便在创建 URL 时提供更大的灵活性。
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
from django.urls import reverse
然后,在我们将调用的模型类上添加类方法Post,包括以下数据库字段:标题、Slug、内容、创建时间和作者。在导入语句下方添加这些字段。
这是文章《如何创建Django模型》的第2部分(共7部分)。
...
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.TextField()
接下来,我们将添加生成URL和保存帖子的功能。这一点非常重要,因为这将为我们的独特帖子创建一个唯一的链接。
模型.py
...
def get_absolute_url(self):
return reverse('blog_post_detail', args=[self.slug])
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
现在,我们需要告诉模型帖子应该如何排序并在网页上显示。这将在一个嵌套的内部 Meta 类中添加逻辑。Meta 类通常包含其他与数据库字段定义无关的重要模型逻辑。
模型.py
...
class Meta:
ordering = ['created_on']
def __unicode__(self):
return self.title
最后,我们将在这个文件中添加 Comment 模型。这涉及到在签名中添加另一个名为 Comment 的类,并定义以下数据库字段:models.Models。
- name — The name of the person posting the comment.
- email — The email address of the person posting the comment.
- text — The text of the comment itself.
- post — The post with which the comment was made.
- created_on — The time the comment was created.
...
class Comment(models.Model):
name = models.CharField(max_length=42)
email = models.EmailField(max_length=75)
website = models.URLField(max_length=200, null=True, blank=True)
content = models.TextField()
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
此时,models.py将会完成。确保你的models.py文件与以下内容一致。
这是文章《如何创建Django模型》的第4部分(共7部分)。
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
from django.urls import reverse
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255)
content = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
author = models.TextField()
def get_absolute_url(self):
return reverse('blog_post_detail', args=[self.slug])
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
class Meta:
ordering = ['created_on']
def __unicode__(self):
return self.title
class Comment(models.Model):
name = models.CharField(max_length=42)
email = models.EmailField(max_length=75)
website = models.URLField(max_length=200, null=True, blank=True)
content = models.TextField()
post = models.ForeignKey(Post, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
请确保保存并关闭文件。如果您在使用nano编辑器,可以通过按下CTRL和X,然后按下Y,然后按下回车键来完成。
有了models.py文件的设置,我们可以继续更新我们的settings.py文件。
步骤3 — 更新设置
现在我们已经在应用程序中添加了模型,必须告知项目我们刚刚创建的博客应用程序的存在。我们通过将它添加到settings.py文件中的INSTALLED_APPS部分来实现这一点。
导航到包含settings.py文件的目录。
- cd ~/my_blog_app/blog/blog
从这里开始,打开settings.py文件,例如使用nano编辑器。
- nano settings.py
文件打开后,按照下面所示,在文件的INSTALLED_APPS部分中添加博客站点应用程序。
# 应用程序定义
INSTALLED_APPS = [
'blogsite',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
添加博客应用程序后,保存并退出文件。
此时,我们已经准备好开始应用这些更改。
第四步 – 进行迁移操作
在模型中添加了Post和Comment之后,下一步是应用这些更改,使MySQL数据库架构能够识别它们并创建所需的表格。
首先,我们必须使用makemigrations命令将模型更改打包成单独的迁移文件。这些文件类似于Git这样的版本控制系统中的提交。
现在,如果导航到~/my_blog_app/blog/blogsite/migrations目录并运行ls命令,会发现只有一个__init__.py文件。一旦我们添加了迁移,这种情况将会改变。
使用cd命令切换到博客目录,如下所示:
- cd ~/my_blog_app/blog
然后在manage.py文件上运行makemigrations命令。
- python manage.py makemigrations
应该在终端窗口中看到以下输出。
Migrations for ‘blogsite’: blogsite/migrations/0001_initial.py – Create model Post – Create model Comment
还记得当我们导航到~/my_blog_app/blog/blogsite/migrations目录时,里面只有一个__init__.py文件吗?如果现在返回该目录,会注意到已经添加了两个项目:__pycache__和0001_initial.py。运行makemigrations时,0001_initial.py文件会自动生成。每次运行makemigrations时,都会生成类似的文件。
如果您想查看该文件的内容,请在所在目录中使用cat命令查看0001_initial.py文件。
现在导航到~/my_blog_app/blog目录。
- cd ~/my_blog_app/blog
既然已经创建了迁移文件,我们必须使用migrate命令将这些文件所描述的修改应用到数据库中。但首先让我们使用showmigrations命令来检查当前存在的迁移。
- python manage.py showmigrations
admin [X] 0001_initial [X] 0002_logentry_remove_auto_add [X] 0003_logentry_add_action_flag_choices auth [X] 0001_initial [X] 0002_alter_permission_name_max_length [X] 0003_alter_user_email_max_length [X] 0004_alter_user_username_opts [X] 0005_alter_user_last_login_null [X] 0006_require_contenttypes_0002 [X] 0007_alter_validators_add_error_messages [X] 0008_alter_user_username_max_length [X] 0009_alter_user_last_name_max_length [X] 0010_alter_group_name_max_length [X] 0011_update_proxy_permissions blogsite [ ] 0001_initial contenttypes [X] 0001_initial [X] 0002_remove_content_type_name sessions [X] 0001_initial
会注意到除了我们刚刚用模型Post和Comment创建的0001_initial迁移之外,所有的迁移都被标记为已应用。
现在让我们检查一下,在进行迁移时会执行哪些SQL语句,使用以下命令。该命令需要接受应用程序名称和迁移名称作为参数。
- python manage.py sqlmigrate blogsite 0001_initial
下面显示的是在后台执行的实际SQL查询。
-- -- Create model Post -- CREATE TABLE `blogsite_post` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `title` varchar(255) NOT NULL, `slug` varchar(255) NOT NULL UNIQUE, `content` longtext NOT NULL, `created_on` datetime(6) NOT NULL, `author` longtext NOT NULL); -- -- Create model Comment -- CREATE TABLE `blogsite_comment` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `name` varchar(42) NOT NULL, `email` varchar(75) NOT NULL, `website` varchar(200) NULL, `content` longtext NOT NULL, `created_on` datetime(6) NOT NULL, `post_id` integer NOT NULL); ALTER TABLE `blogsite_comment` ADD CONSTRAINT `blogsite_comment_post_id_de248bfe_fk_blogsite_post_id` FOREIGN KEY (`post_id`) REFERENCES `blogsite_post` (`id`);
让我们现在执行迁移操作,以便将其应用到我们的MySQL数据库中。
- python manage.py migrate
我们将会得到以下的输出:
Operations to perform: Apply all migrations: admin, auth, blogsite, contenttypes, sessions
Running migrations:
Applying blogsite.0001_initial... OK
你现在已成功应用了迁移。
需要牢记的是,根据Django文档所述,在使用MySQL作为后端时,Django迁移存在三个注意事项。
- 缺乏对模式更改操作周围事务的支持。换句话说,如果迁移未能成功应用,您将必须手动撤销所做的更改,才能尝试另一次迁移。无法回滚到失败迁移中任何更改之前的早期状态。
- 对于大多数模式更改操作,MySQL将完全重写表。在最坏的情况下,时间复杂度将与表中要添加或删除的行数成正比。根据Django文档,这可能慢到每百万行一分钟。
- 在MySQL中,对列、表和索引的名称长度存在较小的限制。对所有列和索引覆盖的组合大小也有限制。虽然其他一些后端可以支持Django中创建的更高限制,但使用MySQL后端时将无法创建相同的索引。
在考虑与Django一起使用的每个数据库时,一定要权衡每个数据库的优缺点。
第五步——验证数据库架构
完成迁移之后,我们应该验证通过 Django 模型创建的 MySQL 表格是否成功生成。
要实现这一点,在终端中运行以下命令来登录到MySQL。我们将使用之前教程中创建的djangouser。
- mysql blog_data -u djangouser
现在,选择我们的数据库blog_data。如果你不知道正在使用的数据库,你可以在SQL中使用SHOW DATABASES;命令显示所有数据库。
- USE blog_data;
然后输入以下命令来查看表格。
- SHOW TABLES;
这个SQL查询应该显示以下内容:
+----------------------------+
| Tables_in_blog_data |
+----------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| blogsite_comment |
| blogsite_post |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
+----------------------------+
12 rows in set (0.01 sec)
在表格中有blogsite_comment和blogsite_post。这些是我们刚刚自己创建的模型。让我们验证一下它们是否包含我们定义的字段。
- DESCRIBE blogsite_comment;
这是文章《如何创建Django模型》的第7部分(共7部分)。
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| name | varchar(42) | NO | | NULL | |
| email | varchar(75) | NO | | NULL | |
| website | varchar(200) | YES | | NULL | |
| content | longtext | NO | | NULL | |
| created_on | datetime(6) | NO | | NULL | |
| post_id | int | NO | MUL | NULL | |
+------------+--------------+------+-----+---------+----------------+
7 行记录 (0.00 秒)
- DESCRIBE blogsite_post;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| title | varchar(255) | NO | | NULL | |
| slug | varchar(255) | NO | UNI | NULL | |
| content | longtext | NO | | NULL | |
| created_on | datetime(6) | NO | | NULL | |
| author | longtext | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
6 行记录 (0.00 秒)
我们已经验证了数据库表格是通过我们的Django模型迁移成功生成的。
当你想要关闭MySQL时,可以使用CTRL + D的组合键。当你准备离开Python环境时,可以运行deactivate命令。
- deactivate
禁用你的编程环境将使你返回到终端命令提示符。
结论
在这个教程中,我们在博客网站应用程序中成功添加了基本功能的模型。您已经学会如何编写模型,迁移工作的原理以及将Django模型转换为实际的MySQL数据库表的过程。