介绍
在上一个教程中,“如何创建Django应用并连接数据库”,我们讨论了如何创建一个MySQL数据库,如何创建和启动Django应用,以及如何将其连接到MySQL数据库。
在本教程中,我们将创建Django 模型,这些模型定义了我们将存储的Blog应用数据的字段和行为。这些模型将你的Django应用程序的数据映射到数据库。这就是Django用来通过对象关系映射(ORM)API生成数据库表的方式,称为“模型”。
先决条件
本教程是Django开发系列的一部分,是该系列的延续。
如果您没有跟随这个系列,我们做出以下假设:
- 您已安装Django版本4或更高版本。
- 您已将您的Django应用连接到数据库。我们正在使用MySQL,您可以通过按照Django系列的第二部分“如何创建Django应用并将其连接到数据库”来实现此连接。
- 您正在使用基于Unix的操作系统,最好是Ubuntu 22.04云服务器,因为这是我们测试的系统。如果您想在类似的环境中设置Django,请参考我们的教程“如何在Ubuntu 22.04上安装Django并设置开发环境”。
由于本教程主要涉及Django模型,即使您的设置略有不同,您也可以跟着进行。
步骤1 — 创建Django应用
为了与Django模块化的理念保持一致,我们将在项目中创建一个Django应用,其中包含创建博客网站所需的所有文件。
每当我们开始在Python和Django中工作时,我们应激活Python虚拟环境并进入我们应用程序的根目录。如果您一直在关注本系列,可以通过输入以下命令来实现这一点。
- cd ~/my_blog_app
- . env/bin/activate
- cd blog
然后,让我们运行这个命令:
- python manage.py startapp blogsite
这将创建我们的应用程序以及一个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
文件。
第2步 – 添加帖子模型
首先,我们需要打开并编辑models.py
文件,以便其中包含生成Post
模型的代码。 Post
模型包含以下数据库字段:
title
— 博客文章的标题。slug
— 存储和生成网页的有效URL的位置。content
— 博客文章的文本内容。created_on
— 帖子创建日期。author
— 撰写帖子的人。
现在,进入包含models.py
文件的目录。
- cd ~/my_blog_app/blog/blogsite
使用cat
命令在终端中显示文件的内容。
- cat models.py
文件应该包含以下代码,其中导入了模型,并附有一条注释,描述应放入此models.py
文件的内容。
from django.db import models
# 在此处创建您的模型。
使用您喜欢的文本编辑器,将以下代码添加到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
,具有以下数据库字段:title
、slug
、content
、created_on
和author
。将这些内容添加到您的导入语句下方。
...
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 和保存帖子的功能。这很重要,因为这会创建一个唯一的链接来匹配我们的唯一帖子。
...
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
类通常包含其他重要的模型逻辑,与数据库字段定义无关。
...
class Meta:
ordering = ['created_on']
def __unicode__(self):
return self.title
最后,我们将在这个文件中添加Comment
模型。这涉及添加另一个名为Comment
的类,其签名中包含models.Models
,并定义以下数据库字段:
name
— 发表评论的人的姓名。email
— 发表评论的人的电子邮件地址。text
— 评论本身的文本。post
— 发表评论的帖子。created_on
— 评论创建时间。
...
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
文件与以下内容相匹配:
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
,然后 ENTER
来执行此操作。
有了设置好的 models.py
文件,我们可以继续更新我们的 settings.py
文件。
第三步 — 更新设置
既然我们已经向应用程序添加了模型,我们必须告知我们的项目刚刚添加的 blogsite
应用程序的存在。我们通过将其添加到 settings.py
中的 INSTALLED_APPS
部分来实现这一点。
导航到包含你的 settings.py
的目录。
- cd ~/my_blog_app/blog/blog
从这里,用 nano 或其他编辑器打开你的 settings.py
文件。
- nano settings.py
文件打开后,按照下面的指示将你的 blogsite
应用程序添加到文件的 INSTALLED_APPS
部分。
# Application definition
INSTALLED_APPS = [
'blogsite',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
添加了blogsite
应用程序后,您可以保存并退出文件。
此时,我们已准备好继续应用这些更改。
步骤 4 — 执行迁移
添加了我们的模型Post
和Comment
之后,下一步是应用这些更改,以便我们的MySQL
数据库架构能够识别它们并创建必要的表。
首先,我们必须将模型更改打包到单独的迁移文件中,使用命令makemigrations
。这些文件类似于版本控制系统(如Git)中的commits
。
现在,如果您导航到~/my_blog_app/blog/blogsite/migrations
并运行ls
,您会注意到只有一个__init__.py
文件。一旦我们添加迁移,这将会改变。
使用cd
切换到博客目录,如下所示:
- cd ~/my_blog_app/blog
然后在manage.py
上运行makemigrations
命令。
- python manage.py makemigrations
然后,您应该在终端窗口中收到以下输出:
OutputMigrations 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
时都会生成类似的文件。
如果您想查看文件的内容,请从所在目录运行less 0001_initial.py
。
现在导航到~/my_blog_app/blog
:
- cd ~/my_blog_app/blog
由于我们已经制作了迁移文件,我们必须使用migrate
命令将这些文件描述的更改应用到数据库。但首先让我们使用showmigrations
命令检查当前存在哪些迁移。
- python manage.py showmigrations
Outputadmin
[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查询。
Output--
-- 创建模型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);
--
-- 创建模型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
我们将收到以下输出:
OutputOperations to perform:
Apply all migrations: admin, auth, blogsite, contenttypes, sessions
Running migrations:
Applying blogsite.0001_initial... OK
你现在已成功应用了你的迁移。
记住,在将MySQL作为后端的Django迁移中有三个注意事项,正如Django文档中所述。
- 缺乏对围绕模式更改操作的事务支持。换句话说,如果迁移无法成功应用,您将不得不手动撤消您所做的更改,以尝试另一个迁移。在失败的迁移中,在任何更改被应用之前,无法回滚到较早的时间点。
- 对于大多数模式更改操作,MySQL将完全重写表。在最坏的情况下,时间复杂度将与要添加或删除列的表中的行数成正比。根据Django文档,这可能慢到每百万行一分钟。
- 在MySQL中,列、表和索引的名称长度存在较小的限制。所有列和索引封面的组合大小也受到限制。虽然其他一些后端可以支持在Django中创建的更高限制,但是在MySQL后端的情况下,相同的索引将无法创建。
对于您考虑用于与Django一起使用的每个数据库,请确保权衡各自的优缺点。
步骤5 — 验证数据库模式
迁移完成后,我们应该验证通过我们的Django模型创建的MySQL表的成功生成。
要执行此操作,请在终端中运行以下命令以登录到MySQL。我们将使用在上一篇教程中创建的djangouser
。
- mysql blog_data -u djangouser
现在,选择我们的数据库blog_data
。如果您不知道正在使用的数据库,您可以使用SHOW DATABASES;
在SQL中显示所有数据库。
- USE blog_data;
然后键入以下命令以查看表格。
- SHOW TABLES;
此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
和blogsite_post
。这些是我们刚刚创建的模型。让我们验证它们是否包含我们定义的字段。
- DESCRIBE blogsite_comment;
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)
- DESCRIBE blogsite_post;
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模型迁移中生成。
您可以使用CTRL
+ D
退出MySQL,当您准备好离开Python环境时,可以运行deactivate
命令:
- deactivate
停用您的编程环境将使您回到终端命令提示符。
结论
在这个教程中,我们已经成功地为博客 Web 应用程序中的基本功能添加了模型。您已经学会了如何编写模型
,以及迁移
的工作原理,以及将 Django 模型
转换为实际MySQL
数据库表的过程。
Source:
https://www.digitalocean.com/community/tutorials/how-to-create-django-models