如何创建Django模型

介绍

在上一个教程中,“如何创建Django应用并连接数据库”,我们讨论了如何创建一个MySQL数据库,如何创建和启动Django应用,以及如何将其连接到MySQL数据库。

在本教程中,我们将创建Django 模型,这些模型定义了我们将存储的Blog应用数据的字段和行为。这些模型将你的Django应用程序的数据映射到数据库。这就是Django用来通过对象关系映射(ORM)API生成数据库表的方式,称为“模型”。

先决条件

本教程是Django开发系列的一部分,是该系列的延续。

如果您没有跟随这个系列,我们做出以下假设:

由于本教程主要涉及Django模型,即使您的设置略有不同,您也可以跟着进行。

步骤1 — 创建Django应用

为了与Django模块化的理念保持一致,我们将在项目中创建一个Django应用,其中包含创建博客网站所需的所有文件。

每当我们开始在Python和Django中工作时,我们应激活Python虚拟环境并进入我们应用程序的根目录。如果您一直在关注本系列,可以通过输入以下命令来实现这一点。

  1. cd ~/my_blog_app
  2. . env/bin/activate
  3. cd blog

然后,让我们运行这个命令:

  1. 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文件的目录。

  1. cd ~/my_blog_app/blog/blogsite

使用cat命令在终端中显示文件的内容。

  1. cat models.py

文件应该包含以下代码,其中导入了模型,并附有一条注释,描述应放入此models.py文件的内容。

models.py
from django.db import models

# 在此处创建您的模型。

使用您喜欢的文本编辑器,将以下代码添加到models.py文件中。我们将使用nano作为我们的文本编辑器,但您可以使用您喜欢的任何编辑器。

  1. nano models.py

在这个文件中,已经添加了导入模型 API 的代码,我们可以继续删除后面的注释。然后,我们将导入slugify用于从字符串生成 slug,导入 Django 的User用于身份验证,以及从django.urls导入reverse以便在创建 URL 时提供更大的灵活性。

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

然后,将模型类上的类方法添加到我们将要调用的Post,具有以下数据库字段:titleslugcontentcreated_onauthor。将这些内容添加到您的导入语句下方。

models.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 和保存帖子的功能。这很重要,因为这会创建一个唯一的链接来匹配我们的唯一帖子。

models.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类通常包含其他重要的模型逻辑,与数据库字段定义无关。

models.py
...
    class Meta:
        ordering = ['created_on']

        def __unicode__(self):
            return self.title

最后,我们将在这个文件中添加Comment模型。这涉及添加另一个名为Comment的类,其签名中包含models.Models,并定义以下数据库字段:

  • name — 发表评论的人的姓名。
  • email — 发表评论的人的电子邮件地址。
  • text — 评论本身的文本。
  • post — 发表评论的帖子。
  • created_on — 评论创建时间。
models.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 文件与以下内容相匹配:

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,可以通过输入 CTRLX,然后 Y,然后 ENTER 来执行此操作。

有了设置好的 models.py 文件,我们可以继续更新我们的 settings.py 文件。

第三步 — 更新设置

既然我们已经向应用程序添加了模型,我们必须告知我们的项目刚刚添加的 blogsite 应用程序的存在。我们通过将其添加到 settings.py 中的 INSTALLED_APPS 部分来实现这一点。

导航到包含你的 settings.py 的目录。

  1. cd ~/my_blog_app/blog/blog

从这里,用 nano 或其他编辑器打开你的 settings.py 文件。

  1. nano settings.py

文件打开后,按照下面的指示将你的 blogsite 应用程序添加到文件的 INSTALLED_APPS 部分。

settings.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应用程序后,您可以保存并退出文件。

此时,我们已准备好继续应用这些更改。

步骤 4 — 执行迁移

添加了我们的模型PostComment之后,下一步是应用这些更改,以便我们的MySQL数据库架构能够识别它们并创建必要的表。

首先,我们必须将模型更改打包到单独的迁移文件中,使用命令makemigrations。这些文件类似于版本控制系统(如Git)中的commits

现在,如果您导航到~/my_blog_app/blog/blogsite/migrations并运行ls,您会注意到只有一个__init__.py文件。一旦我们添加迁移,这将会改变。

使用cd切换到博客目录,如下所示:

  1. cd ~/my_blog_app/blog

然后在manage.py上运行makemigrations命令。

  1. python manage.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文件吗?如果我们现在返回到那个目录,我们会注意到添加了两个项目:__pycache__0001_initial.py。当您运行makemigrations时,0001_initial.py文件会自动生成。每次运行makemigrations时都会生成类似的文件。

如果您想查看文件的内容,请从所在目录运行less 0001_initial.py

现在导航到~/my_blog_app/blog

  1. cd ~/my_blog_app/blog

由于我们已经制作了迁移文件,我们必须使用migrate命令将这些文件描述的更改应用到数据库。但首先让我们使用showmigrations命令检查当前存在哪些迁移。

  1. python manage.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

您会注意到除了我们刚刚使用模型PostComment创建的0001_initial之外,所有迁移都已检查。

现在让我们使用以下命令检查一旦我们进行迁移将执行哪些SQL语句。它接受迁移和迁移标题作为参数:

  1. 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数据库中。

  1. python manage.py migrate

我们将收到以下输出:

Output
Operations 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

  1. mysql blog_data -u djangouser

现在,选择我们的数据库blog_data。如果您不知道正在使用的数据库,您可以使用SHOW DATABASES;在SQL中显示所有数据库。

  1. USE blog_data;

然后键入以下命令以查看表格。

  1. 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_commentblogsite_post。这些是我们刚刚创建的模型。让我们验证它们是否包含我们定义的字段。

  1. 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)
  1. 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命令:

  1. deactivate

停用您的编程环境将使您回到终端命令提示符。

结论

在这个教程中,我们已经成功地为博客 Web 应用程序中的基本功能添加了模型。您已经学会了如何编写模型,以及迁移的工作原理,以及将 Django 模型转换为实际MySQL数据库表的过程。

Source:
https://www.digitalocean.com/community/tutorials/how-to-create-django-models