在之前的教程中,“如何创建 Django 应用程序并将其连接到数据库,”我们介绍了如何创建 MySQL 数据库、如何创建和启动 Django 应用程序以及如何将其连接到 MySQL 数据库。
在本教程中,我们将创建 Djangomodels定义我们将存储的博客应用程序数据的字段和行为。这些模型将数据从 Django 应用程序映射到数据库。 Django 使用它通过对象关系映射 (ORM) API(称为“模型”)生成数据库表。
本教程是Django开发系列是该系列的延续。
如果您尚未阅读本系列文章,我们将做出以下假设:
- 您已安装 Django 版本 4 或更高版本。
- 您已将 Django 应用程序连接到数据库。我们使用的是 MySQL,您可以通过遵循 Django 系列的第二部分来实现此连接,“如何创建 Django 应用程序并将其连接到数据库.”
- 您正在使用基于 Unix 的操作系统,最好是 Ubuntu 22.04 云服务器,因为这是我们测试过的系统。如果您想在类似的环境中设置 Django,请参阅我们的教程“如何在 Ubuntu 22.04 上安装 Django 并设置开发环境.”
由于本教程主要涉及 Django 模型,因此即使您的设置有所不同,您也可以继续学习。
为了与 Django 模块化理念保持一致,我们将在项目中创建一个 Django 应用程序,其中包含创建博客网站所需的所有文件。
每当我们开始使用 Python 和 Django 进行工作时,我们都应该激活 Python 虚拟环境并移至应用程序的根目录。如果您按照本系列进行操作,则可以通过键入以下内容来实现此目的。
-
cd〜/我的博客应用程序
-
.环境/bin/激活
-
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
我们将在本教程中重点关注的文件是models.py
文件,该文件位于blogsite
目录。
首先我们需要打开并编辑models.py
文件,以便它包含生成的代码Post
模型。 APost
模型包含以下数据库字段:
-
title
— 博客文章的标题。
-
slug
— 为网页存储和生成有效 URL 的位置。
-
content
— 博客文章的文本内容。
-
created_on
— 帖子创建的日期。
-
author
— 写这篇文章的人。
现在,移动到该目录models.py
文件已包含。
-
cd〜/ my_blog_app /博客/博客网站
Use the cat
命令在终端中显示文件的内容。
该文件应包含以下代码,用于导入模型,以及描述要放入其中的内容的注释models.py
file.
模型.py
from django.db import models
# Create your models here.
使用您最喜欢的文本编辑器,将以下代码添加到models.py
文件。我们将使用nano
作为我们的文本编辑器,但欢迎您使用您喜欢的任何内容。
在这个文件中,已经添加了导入模型 API 的代码,我们可以继续删除后面的注释。然后我们将导入slugify
用于从字符串生成 slugs,Django 的User
用于身份验证,以及reverse
from django.urls
为我们创建 URL 提供更大的灵活性。
模型.py
from django.db import models
from django.template.defaultfilters import slugify
from django.contrib.auth.models import User
from django.urls import reverse
然后,在我们将调用的模型类上添加类方法Post
,具有以下数据库字段,title
, slug
, content
, created_on
and author
。将这些添加到您的导入语句下方。
模型.py
...
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
with models.Models
在其签名和定义的以下数据库字段中:
-
name
— 发表评论的人的姓名。
-
email
— 发表评论的人的电子邮件地址。
-
text
— 评论本身的文本。
-
post
— 发表评论的帖子。
-
created_on
— 评论创建的时间。
模型.py
...
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
文件匹配以下内容:
模型.py
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
and X
, then Y
, then ENTER
.
随着models.py
文件设置完毕,我们可以继续更新我们的settings.py
file.
现在我们已经将模型添加到我们的应用程序中,我们必须告知我们的项目存在blogsite
我们刚刚添加的应用程序。我们通过将其添加到INSTALLED_APPS
部分在settings.py
.
导航到您的目录settings.py
lives.
从这里开始,打开您的settings.py
文件,例如 nano。
打开文件后,添加您的blogsite
应用程序到INSTALLED_APPS
文件的部分,如下所示。
设置.py
# Application definition
INSTALLED_APPS = [
'blogsite',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
随着blogsite
添加应用程序后,您可以保存并退出文件。
此时,我们已准备好继续应用这些更改。
与我们的模型Post
and Comment
补充说,下一步是应用这些更改,以便我们的MySQL
数据库模式识别它们并创建必要的表。
首先,我们必须使用以下命令将模型更改打包到单独的迁移文件中makemigrations
。这些文件类似于commits
在像 Git 这样的版本控制系统中。
现在,如果您导航到~/my_blog_app/blog/blogsite/migrations
并运行ls
,你会注意到只有一个__init__.py
文件。一旦我们添加迁移,这种情况就会改变。
使用更改到博客目录cd
,像这样:
然后运行makemigrations
命令开启manage.py
.
- python 管理.py makemigrations
然后,您应该在终端窗口中收到以下输出:
Output
Migrations for 'blogsite':
blogsite/migrations/0001_initial.py
- Create model Post
- Create model Comment
请记住,当我们导航到/~/my_blog_app/blog/blogsite/migrations
它只有__init__.py
文件?如果我们现在cd
回到该目录,我们会注意到添加了两项:__pycache__
and 0001_initial.py
. The 0001_initial.py
文件是运行时自动生成的makemigrations
。每次运行都会生成一个类似的文件makemigrations
.
Run less 0001_initial.py
如果您想阅读该文件包含的内容,请从该文件所在的目录中查看。
现在导航到~/my_blog_app/blog
:
由于我们已经创建了迁移文件,因此我们必须使用以下命令将这些文件描述的更改应用到数据库migrate
。但首先让我们检查当前存在哪些迁移,使用showmigrations
命令。
- python 管理.py showmigrations
Output
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
您会注意到,除以下迁移外,所有迁移均已检查0001_initial
我们刚刚用模型创建的Post
and Comment
.
现在让我们检查一下是哪个SQL
一旦我们使用以下命令进行迁移,就会执行语句。它接受迁移和迁移的标题作为参数:
- python manage.py sqlmigrate 博客站点 0001_initial
下面显示的是在幕后进行的实际 SQL 查询。
Output
--
-- 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 数据库。
我们将收到以下输出:
Output
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
。如果您不知道正在使用的数据库,可以使用以下命令显示所有数据库SHOW DATABASES;
in SQL.
然后键入以下命令来查看表。
此 SQL 查询应显示以下内容:
Output
+----------------------------+
| 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
and blogsite_post
。这些是我们刚刚自己制作的模型。让我们验证它们是否包含我们定义的字段。
Output
+------------+--------------+------+-----+---------+----------------+
| 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 rows in set (0.00 sec)
Output
+------------+--------------+------+-----+---------+----------------+
| 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 rows in set (0.00 sec)
我们已验证数据库表已从 Django 模型迁移中成功生成。
您可以使用以下命令关闭 MySQLCTRL
+ D
当您准备好离开 Python 环境时,您可以运行deactivate
命令:
停用编程环境将使您返回终端命令提示符。
在本教程中,我们成功地在博客 Web 应用程序中添加了基本功能的模型。您已经学会了如何编码models
, how migrations
工作以及翻译Django的过程models
到实际的MySQL
数据库表。