Django--02模型和管理站点
Django–02模型与站点管理
本教程承接Django–01的内容。我们将设置数据库、创建你的第一个模型,并快速了解 Django 自动生成的管理站点。
文章目录
- Django--02模型与站点管理
- 一、设置数据库
- 1.1 参考文档链接
- 1.2 默认设置
- 1.3 极简主义者
- 二、创建模型
- 2.1 设计理念
- 三、激活模型
- 3.1 设计理念
- 四、调用API
- 五、介绍 Django 管理界面
- 5.1 设计理念
- 5.2 创建管理员用户
- 5.3 进入管理站点
- 5.4 让投票应用在管理界面中可修改
- 5.5 探索免费的管理功能
一、设置数据库
1.1 参考文档链接
https://docs.djangoproject.com/en/5.2/topics/install/#database-installation
1.2 默认设置
现在,打开mysite/settings.py。这是一个普通的 Python 模块,其中包含表示 Django 设置的模块级变量。
默认情况下,DATABASES配置使用 SQLite。如果你是数据库新手,或者只是想尝试 Django,这是最简单的选择。SQLite
已包含在 Python 中,因此你无需安装其他任何东西来支持数据库。但是,当开始你的第一个实际项目时,你可能希望使用更具可扩展性的数据库(如
PostgreSQL),以避免日后切换数据库带来的麻烦。 如果你想使用其他数据库,请查看相关细节以自定义并运行你的数据库。
在编辑mysite/settings.py时,将TIME_ZONE设置为你的时区。中国北京设置为"Asia/Shanghai"
另外,注意文件顶部的INSTALLED_APPS设置。它包含了在这个 Django 实例中激活的所有 Django
应用的名称。应用可以在多个项目中使用,你还可以打包并分发它们,供其他人在其项目中使用。
默认情况下,INSTALLED_APPS包含以下应用,所有这些应用都随 Django 一起提供:
django.contrib.admin – 管理站点。你很快就会用到它。
django.contrib.auth – 认证系统。
django.contrib.contenttypes – 内容类型框架。
django.contrib.sessions – 会话框架。
django.contrib.messages – 消息框架。
django.contrib.staticfiles – 管理静态文件的框架。
这些应用默认包含在内,是为了方便处理常见场景。
不过,这些应用中有些需要至少一个数据库表才能使用,因此在使用它们之前,我们需要在数据库中创建这些表。为此,运行以下命令:
py manage.py migrate
migrate命令会查看INSTALLED_APPS设置,并根据mysite/settings.py文件中的数据库设置以及应用附带的数据库迁移文件(我们稍后会介绍),创建所有必要的数据库表。你会看到它应用的每个迁移的相关消息。如果感兴趣,可以运行数据库的命令行客户端,输入\dt(PostgreSQL)、SHOW TABLES;(MariaDB、MySQL)、.tables(SQLite)或SELECT TABLE_NAME FROM USER_TABLES;(Oracle)来查看 Django 创建的表。
1.3 极简主义者
如前所述,默认应用是为常见场景准备的,但并非所有人都需要它们。如果不需要其中任何一个或全部应用,可以在运行migrate之前,从INSTALLED_APPS中注释或删除相应的行。migrate命令只会为INSTALLED_APPS中的应用运行迁移。
二、创建模型
现在我们将定义模型 —— 本质上是你的数据库布局,附带额外的元数据。
2.1 设计理念
模型是关于数据的唯一、权威的信息来源。它包含你要存储的数据的基本字段和行为。Django 遵循 DRY 原则(Don’t Repeat Yourself,即 “不要重复自己”)。目标是在一个地方定义数据模型,并从中自动派生其他内容。
这包括迁移 —— 与 Ruby On Rails 等框架不同,迁移完全源自你的模型文件,本质上是 Django 可以逐步执行的历史记录,用于将数据库架构更新为与当前模型匹配的状态。
在我们的投票应用中,我们将创建两个模型:Question和Choice。Question包含一个问题文本和一个发布日期。Choice包含两个字段:选项文本和投票计数。每个Choice都与一个Question相关联。
这些概念由 Python 类表示。编辑polls/models.py文件,使其如下所示:
from django.db import modelsclass Question(models.Model):question_text = models.CharField(max_length=200)pub_date = models.DateTimeField("date published")class Choice(models.Model):question = models.ForeignKey(Question, on_delete=models.CASCADE)choice_text = models.CharField(max_length=200)votes = models.IntegerField(default=0)
这里,每个模型都由一个继承自django.db.models.Model的类表示。每个模型都有多个类变量,每个类变量都代表模型中的一个数据库字段。
每个字段由Field类的实例表示 —— 例如,CharField用于字符字段,DateTimeField用于日期时间字段。这告诉 Django 每个字段存储的数据类型。
每个Field实例的名称(例如question_text或pub_date)是字段的机器可读名称。你会在 Python 代码中使用这个值,数据库也会将其用作列名。
你可以为Field提供一个可选的第一个位置参数,指定一个人类可读的名称。它用于 Django 的一些自省部分,同时也起到文档的作用。如果没有提供这个字段,Django 将使用机器可读的名称。在这个例子中,我们只为Question.pub_date定义了人类可读的名称。对于该模型中的所有其他字段,字段的机器可读名称足以作为其人类可读名称。
有些Field类有必需的参数。例如,CharField要求你给它一个max_length。这不仅用于数据库架构,还用于验证,我们很快就会看到。
Field还可以有各种可选参数;在这种情况下,我们将votes的default值设置为 0。
最后,注意使用ForeignKey定义了一个关系。这告诉 Django 每个Choice都与一个Question相关联。Django 支持所有常见的数据库关系:多对一、多对多和一对一。
三、激活模型
那一小段模型代码为 Django 提供了大量信息。有了它,Django 能够:
为此应用程序创建数据库架构 ( statements)。CREATE TABLE创建一个 Python 数据库访问 API,用于访问对象Question和Choice。
但首先我们需要告诉我们的项目应用程序已安装polls
3.1 设计理念
Django 应用是 “可插拔的”:你可以在多个项目中使用一个应用,并且可以分发应用,因为它们不必绑定到特定的 Django 安装。
要将应用包含在我们的项目中,我们需要在INSTALLED_APPS设置中添加对其配置类的引用。PollsConfig类位于polls/apps.py文件中,因此其 dotted 路径是’polls.apps.PollsConfig’。编辑mysite/settings.py文件,将该 dotted 路径添加到INSTALLED_APPS设置中。修改后如下所示:
类似导包
现在 Django 知道要包含 “polls” 应用了。让我们运行另一个命令:
py manage.py makemigrations polls
会看到下面的内容
- 通过运行makemigmigrations,你告诉Django你已经对你的模型做了一些改变(在这个例子中,你已经做了一些新的),并且你想把这些改变作为迁移存储起来。
- 迁移是Django将更改存储到模型(以及数据库模式)的方式——它们是磁盘上的文件。 如果愿意,您可以阅读新模型的迁移;它是文件polls/migrations/eee1_initial.py。
- 别担心,你不需要每次Django创建一个文件都去阅读它们,但是如果你想手动调整Django的更改方式,它们被设计为可编辑的。
有一个命令可以为你运行迁移并自动管理数据库架构 —— 那就是migrate,我们稍后会用到它 —— 但首先,让我们看看这个迁移会运行什么 SQL。sqlmigrate命令接受迁移名称并返回它们的 SQL:
py manage.py sqlmigrate polls 0001
请注意以下几点:
- 具体的输出结果会因您所使用的数据库而有所不同。上述示例是针对 PostgreSQL 系统生成的。
- 表名会通过将应用程序名称(“投票”)与模型问题及选项的首字母小写形式相结合的方式自动生成。(您可以更改此设置。)
- 主键(标识符)会自动添加。(您也可以对其进行更改。)
- 按照惯例,Django会在外键字段名称后加上“_id”(当然,您也可以对其进行修改)。
- 外键关系通过“FOREIGNKEY”约束得以明确表示。无需担心“可撤销”部分的内容;它所表达的意思是… PostgreSQL在事务结束前不会强制执行外键约束。
- 它会根据您所使用的数据库进行定制,因此诸如自动递增(MySQL)、大整数主键(默认生成且自动作为标识符,PostgreSQL)或整数主键自动递增(SQLite)等特定于数据库的字段类型都会自动为您处理好。对于字段名称的引号使用方式也是如此——例如,使用双引号或单引号。
- “sqlmigrate”命令实际上并不会在您的数据库上执行迁移操作——相反,它会将迁移内容打印到屏幕上,以便您能够查看 Django认为需要执行的 SQL 语句。这对于检查 Django 将要执行的操作非常有用,或者如果您有需要 SQL脚本来完成更改的数据库管理员,它也非常适用。
如果您感兴趣的话,还可以运行python manage.pycheck
命令;此命令可检查您的项目中是否存在任何问题,且无需进行迁移操作或修改数据库。
现在,再次运行“迁移”操作,以便在您的数据库中创建那些模型表:
py manage.py migrate
“migrate”命令会获取所有尚未应用的迁移文件(Django 通过数据库中一个名为“django migrations”的特殊表来记录哪些迁移已应用)并将其应用于您的数据库——本质上就是将您对模型所做的更改与数据库中的架构进行同步。
迁移功能非常强大,能够让您在项目开发过程中根据需要不断修改模型,而无需删除现有的数据库或表,然后重新创建新的——它专门用于在不丢失数据的情况下实时升级数据库。
现在请记住进行模型更改的三个步骤指南:
- 修改你的模型(在 models.py 文件中)。
- 运行命令以针对这些更改创建迁移文件。
python manage.py makemigrations
- 运行“python manage.pymigrate”命令以将这些更改应用到数据库中。
之所以会有专门的命令来执行和应用迁移操作,是因为您会将迁移操作提交到版本控制系统中,并将其与应用程序一同发布;这些迁移不仅能让您的开发工作更加便捷,而且还能被其他开发人员使用,并在生产环境中发挥作用。
四、调用API
现在,让我们进入交互式 Python shell,体验一下 Django 提供的免费 API。要调用 Python shell,请使用以下命令:
py manage.py shell
进入 shell 后,探索数据库 API:
我们使用这个命令而不是简单地输入 “python”,是因为manage.py会设置DJANGO_SETTINGS_MODULE环境变量,该变量为 Django 提供了 Python 导入路径到你的mysite/settings.py文件。默认情况下,shell命令会自动导入你INSTALLED_APPS中的模型。
进入 shell 后,探索数据库 API:
# 目前系统中还没有问题。
>>> Question.objects.all()
<QuerySet []># 默认设置中启用了时区支持,因此
# Django期望pub_date是一个带tzinfo的datetime。使用timezone.now()
# 而不是datetime.datetime.now(),它会处理正确的时区。
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())# 要将对象保存到数据库中,必须显式调用save()。
>>> q.save()# 现在它有了一个ID。
>>> q.id
1# 通过Python属性访问模型字段值。
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=datetime.timezone.utc)# 通过更改属性值,然后调用save()来修改值。
>>> q.question_text = "What's up?"
>>> q.save()# objects.all()显示数据库中的所有问题。
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>
<Question: Question object (1)> 并不是这个对象的有用表示。让我们通过编辑Question模型(在polls/models.py文件中)并为Question和Choice添加__str__()方法来修复这个问题:
# polls/models.py
from django.db import modelsclass Question(models.Model):# ...def __str__(self):return self.question_textclass Choice(models.Model):# ...def __str__(self):return self.choice_text
为模型添加__str__()方法非常重要,不仅是为了在处理交互式提示时方便自己,还因为对象的表示会在 Django 自动生成的管理界面中使用。
我们还可以为这个模型添加一个自定义方法:
# polls/models.py
import datetime
from django.db import models
from django.utils import timezoneclass Question(models.Model):# ...def was_published_recently(self):return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
总而言之,把polls/models.py修改为下面的样子
import datetimefrom django.db import models
from django.utils import timezoneclass Question(models.Model):question_text = models.CharField(max_length=200)pub_date = models.DateTimeField("date published")def __str__(self):return self.question_textdef was_published_recently(self):return self.pub_date >= timezone.now() - datetime.timedelta(days=1)class Choice(models.Model):question = models.ForeignKey(Question, on_delete=models.CASCADE)choice_text = models.CharField(max_length=200)votes = models.IntegerField(default=0)def __str__(self):return self.choice_text# Create your models here.
保存这些更改,然后通过运行python manage.py shell再次启动新的 Python 交互式 shell:
# 确保我们添加的__str__()方法起作用了。
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]># Django提供了丰富的数据库查询API,完全由
# 关键字参数驱动。
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith="What")
<QuerySet [<Question: What's up?>]># 获取今年发布的问题。
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?># 请求一个不存在的ID,这会引发异常。
>>> Question.objects.get(id=2)
Traceback (most recent call last):...
DoesNotExist: Question matching query does not exist.# 通过主键查找是最常见的情况,所以Django为精确的主键查找提供了一个快捷方式。
# 以下等同于Question.objects.get(id=1)。
>>> Question.objects.get(pk=1)
<Question: What's up?># 确保我们的自定义方法起作用了。
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True# 给这个问题添加几个选项。create调用会构造一个新的
# Choice对象,执行INSERT语句,将选项添加到可用选项集中
# 并返回新的Choice对象。Django创建一个集合(定义为"choice_set")来保存外键关系的"另一端"
# (例如,一个问题的选项),可以通过API访问。
>>> q = Question.objects.get(pk=1)# 显示相关对象集中的任何选项——目前还没有。
>>> q.choice_set.all()
<QuerySet []># 创建三个选项。
>>> q.choice_set.create(choice_text="Not much", votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text="The sky", votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text="Just hacking again", votes=0)# Choice对象可以通过API访问它们相关的Question对象。
>>> c.question
<Question: What's up?># 反之亦然:Question对象可以访问Choice对象。
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3# API可以根据需要自动跟踪关系。
# 使用双下划线分隔关系。
# 这可以深入多个层级;没有限制。
# 查找所有在今年发布的问题的选项
# (重用我们上面创建的'current_year'变量)。
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]># 让我们删除其中一个选项。使用delete()方法。
>>> c = q.choice_set.filter(choice_text__startswith="Just hacking")
>>> c.delete()
五、介绍 Django 管理界面
5.1 设计理念
为员工或客户生成用于添加、修改和删除内容的管理站点是一项繁琐的工作,不需要太多创造力。因此,Django 完全自动化了模型管理界面的创建。
Django 是在新闻编辑室环境中编写的,“内容发布者” 和 “公共” 站点之间有明确的区分。站点管理员使用该系统添加新闻报道、事件、体育比分等,这些内容会显示在公共站点上。Django 解决了为站点管理员创建统一内容编辑界面的问题。
管理界面并非为站点访问者设计,而是为站点管理者设计的。
5.2 创建管理员用户
首先,我们需要创建一个可以登录管理站点的用户。运行以下命令:
py manage.py createsuperuser
输入你想要的用户名并按回车。
Username: admin
然后会提示你输入所需的电子邮件地址:
Email address: admin@example.com
最后一步是输入你的密码。系统会要求你输入两次密码,第二次是为了确认第一次输入的密码。
Password: **********
Password (again): *********
Superuser created successfully.
现在,打开 Web 浏览器,访问你本地域名的 “/admin/” 路径 —— 例如,http://127.0.0.1:8000/admin/。你应该会看到管理界面的登录屏幕:
5.3 进入管理站点
现在,尝试使用你在前面步骤中创建的超级用户账户登录。你应该会看到 Django 管理索引页面:
你应该会看到几种可编辑的内容:组和用户。它们由django.contrib.auth提供,这是 Django 附带的认证框架。
5.4 让投票应用在管理界面中可修改
但是我们的投票应用在哪里呢?它没有显示在管理索引页面上。
只需要再做一件事:我们需要告诉管理界面Question对象有一个管理界面。为此,打开polls/admin.py文件,编辑它如下:
# polls/admin.py
from django.contrib import adminfrom .models import Questionadmin.site.register(Question)
5.5 探索免费的管理功能
现在我们已经注册了Question,Django 知道它应该显示在管理索引页面上:
点击 “Questions”。现在你在问题的 “更改列表” 页面。这个页面显示数据库中的所有问题,让你可以选择一个进行修改。这里有我们之前创建的 “What’s up?” 问题:
请注意以下几点:
- 表单是根据Question模型自动生成的。
- 不同的模型字段类型(DateTimeField、CharField)对应相应的 HTML输入控件。每种类型的字段都知道如何在 Django 管理界面中显示自己。
- 每个DateTimeField都有免费的 JavaScript快捷方式。日期有 “今天” 快捷方式和日历弹窗,时间有 “现在” 快捷方式和一个方便的常用时间弹窗。
- 页面底部为你提供了几个选项:
1.保存(Save)—— 保存更改并返回到该类型对象的更改列表页面。
2. 保存并继续编辑(Save and continue editing)—— 保存更改并重新加载该对象的管理页面。
3. 保存并添加另一个(Save and add another)——保存更改并加载该类型对象的新空白表单。
4. 删除(Delete)—— 显示删除确认页面。
如果 “Date published” 的值与你在教程 1 中创建问题的时间不匹配,可能是因为你忘记设置TIME_ZONE的正确值。更改它,重新加载页面,检查是否显示正确的值。
通过点击 “Today” 和 “Now” 快捷方式更改 “Date published”。然后点击 “Save and continue editing”。然后点击右上角的 “History”。你会看到一个页面,列出通过 Django 管理界面对此对象所做的所有更改,包括更改的时间戳和做出更改的用户名: