Skip to main content

编写你的第一个 Django 应用程序,第 2 部分

官网链接

本教程从教程 1结束的地方开始。我们将设置数据库,创建您的第一个模型,并快速介绍 Django 自动生成的管理站点。

从哪里获得帮助:

如果您在完成本教程时遇到问题,请转到常见问题解答的“获取帮助”部分。

数据库设置

现在,打开mysite/settings.py。它是一个普通的 Python 模块,具有代表 Django 设置的模块级变量。

默认情况下,配置使用 SQLite。如果您是数据库新手,或者您只是有兴趣尝试 Django,那么这是最简单的选择。 SQLite 包含在 Python 中,因此您无需安装任何其他内容来支持您的数据库。然而,当开始您的第一个实际项目时,您可能希望使用更具可扩展性的数据库,例如 PostgreSQL,以避免日后数据库切换的麻烦。

如果您希望使用其他数据库,请安装适当的数据库绑定并更改项目中的以下键 以匹配您的数据库连接设置:DATABASES 'default'

  • ENGINE- 'django.db.backends.sqlite3'两者 'django.db.backends.postgresql''django.db.backends.mysql''django.db.backends.oracle'。其他后端也可用
  • NAME– 您的数据库的名称。如果您使用 SQLite,数据库将是您计算机上的一个文件;在这种情况下,NAME 应该是该文件的完整绝对路径,包括文件名。默认值会将文件存储在您的项目目录中。BASE_DIR / 'db.sqlite3'

如果您不使用 SQLite 作为数据库,则必须添加其他设置,例如 USERPASSWORD和。HOST有关更多详细信息,请参阅 的参考文档DATABASES

对于 SQLite 以外的数据库

如果您使用的是 SQLite 之外的数据库,请确保此时您已经创建了数据库。在数据库的交互式提示中使用“ ”来执行此操作。CREATE DATABASE database_name;

还要确保提供的数据库用户mysite/settings.py 具有“创建数据库”权限。这允许自动创建 测试数据库,稍后的教程将需要该数据库。

如果您使用 SQLite,则无需事先创建任何内容 - 数据库文件将在需要时自动创建。

在编辑时mysite/settings.py,设置TIME_ZONE您的时区。

另请注意INSTALLED_APPS文件顶部的设置。它保存在此 Django 实例中激活的所有 Django 应用程序的名称。应用程序可以在多个项目中使用,您可以打包并分发它们以供其他人在其项目中使用。

默认情况下,INSTALLED_APPS包含以下应用程序,所有这些应用程序都附带 Django:

默认情况下包含这些应用程序是为了方便常见情况。

不过,其中一些应用程序至少使用一个数据库表,因此我们需要先在数据库中创建这些表,然后才能使用它们。为此,请运行以下命令:

...\> py 管理.py 迁移

migrate命令查看INSTALLED_APPS设置并根据mysite/settings.py文件中的数据库设置以及应用程序附带的数据库迁移创建任何必要的数据库表(我们将在稍后介绍这些内容)。对于它应用的每个迁移,您都会看到一条消息。如果您有兴趣,请运行数据库的命令行客户端并输入\dt(PostgreSQL)、(MariaDB、MySQL)、 (SQLite) 或(Oracle) 以显示 Django 创建的表。SHOW TABLES;``.tables``SELECT TABLE_NAME FROM USER_TABLES;

对于极简主义者来说

正如我们上面所说,默认应用程序包含在常见情况下,但并不是每个人都需要它们。如果您不需要其中任何或全部,请随时注释掉或INSTALLED_APPS在运行之前删除相应的行 migrate。该 migrate命令将仅对 INSTALLED_APPS.

创建模型

现在我们将定义您的模型 - 本质上是您的数据库布局,以及附加元数据。

哲学

模型是有关数据的单一、明确的信息源。它包含您所存储的数据的基本字段和行为。 Django 遵循DRY 原则。目标是在一个地方定义数据模型并自动从中派生数据。

这包括迁移 - 与 Ruby On Rails 不同,例如,迁移完全源自模型文件,并且本质上是 Django 可以滚动更新数据库架构以匹配当前模型的历史记录。

在我们的民意调查应用程序中,我们将创建两个模型:QuestionChoice。 A Question有一个问题和发布日期。 AChoice有两个字段:选择的文本和投票计数。每个都Choice与一个相关联Question

这些概念由 Python 类表示。编辑该 polls/models.py文件,使其看起来像这样:

polls/models.py

from django.db import models


class 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_textpub_date)是字段的名称,采用机器友好的格式。您将在 Python 代码中使用此值,并且数据库将使用它作为列名称。

您可以使用 a 的可选第一个位置参数来 Field指定人类可读的名称。它用在 Django 的几个内省部分中,并且还兼作文档。如果未提供此字段,Django 将使用机器可读的名称。在此示例中,我们仅定义了一个人类可读的名称Question.pub_date。对于此模型中的所有其他字段,字段的机器可读名称足以作为其人类可读名称。

有些Field类需要参数。 CharField例如,要求您给它一个 max_length.这不仅用于数据库模式,还用于验证,我们很快就会看到。

AField还可以有各种可选参数;在本例中,我们将default的值 设置votes为 0。

最后,请注意使用 定义了关系 ForeignKey。这告诉 Django 每个都Choice与一个相关Question。 Django 支持所有常见的数据库关系:多对一、多对多和一对一。

激活模型

这一小段模型代码为 Django 提供了大量信息。有了它,Django 能够:

  • 为此应用程序创建数据库架构(语句)。CREATE TABLE
  • Question创建用于访问对象的 Python 数据库访问 API Choice

但首先我们需要告诉我们的项目该polls应用程序已安装。

哲学

Django 应用程序是“可插入的”:您可以在多个项目中使用一个应用程序,并且可以分发应用程序,因为它们不必绑定到给定的 Django 安装。

要将应用程序包含在我们的项目中,我们需要在设置中添加对其配置类的引用INSTALLED_APPS。该类 PollsConfig位于polls/apps.py文件中,因此其点路径为'polls.apps.PollsConfig'.编辑mysite/settings.py文件并将该点路径添加到INSTALLED_APPS设置中。它看起来像这样:

mysite/settings.py

INSTALLED_APPS = [
"polls.apps.PollsConfig",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]

现在 Django 知道要包含该polls应用程序。让我们运行另一个命令:

...\> py manage.py makemigrations 民意调查

您应该看到类似于以下内容的内容:

Migrations for 'polls':
polls/migrations/0001_initial.py
- Create model Question
- Create model Choice

通过运行makemigrations,您告诉 Django 您已经对模型进行了一些更改(在本例中,您已经进行了新的更改)并且您希望将更改存储为迁移

迁移是 Django 存储对模型(以及数据库模式)的更改的方式 - 它们是磁盘上的文件。如果您愿意,可以阅读新模型的迁移;这是文件polls/migrations/0001_initial.py。别担心,您不需要在 Django 每次制作时都阅读它们,但它们被设计为可供人工编辑,以防您想要手动调整 Django 更改内容的方式。

有一个命令可以为您运行迁移并自动管理您的数据库架构 - 这就是所谓的migrate,我们稍后会介绍它 - 但首先,让我们看看该迁移将运行哪些 SQL。该 sqlmigrate命令获取迁移名称并返回其 SQL:

...\> py manage.py sqlmigrate 轮询 0001

您应该看到类似于以下内容的内容(为了便于阅读,我们对其进行了重新格式化):

BEGIN;
--
-- Create model Question
--
CREATE TABLE "polls_question" (
"id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
"question_text" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
--
-- Create model Choice
--
CREATE TABLE "polls_choice" (
"id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
"choice_text" varchar(200) NOT NULL,
"votes" integer NOT NULL,
"question_id" bigint NOT NULL
);
ALTER TABLE "polls_choice"
ADD CONSTRAINT "polls_choice_question_id_c5b4b260_fk_polls_question_id"
FOREIGN KEY ("question_id")
REFERENCES "polls_question" ("id")
DEFERRABLE INITIALLY DEFERRED;
CREATE INDEX "polls_choice_question_id_c5b4b260" ON "polls_choice" ("question_id");

COMMIT;

请注意以下事项:

  • 确切的输出将根据您使用的数据库而有所不同。上面的示例是为 PostgreSQL 生成的。
  • 表名称是通过组合应用程序名称 ( polls) 和模型的小写名称 -question和 来自动生成的choice。 (您可以覆盖此行为。)
  • 主键 (ID) 会自动添加。 (您也可以覆盖它。)
  • 按照约定,Django 附加"_id"到外键字段名称。 (是的,您也可以覆盖它。)
  • 外键关系通过约束变得明确 。不用担心零件;它告诉 PostgreSQL 在事务结束之前不要强制执行外键。FOREIGN KEY``DEFERRABLE
  • 它是根据您使用的数据库量身定制的,因此会自动为您处理数据库特定的字段类型,例如auto_increment(MySQL)、(PostgreSQL) 或(SQLite)。字段名称的引用也是如此——例如,使用双引号或单引号。bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY``integer primary key autoincrement
  • sqlmigrate命令实际上并不在您的数据库上运行迁移 - 相反,它将其打印到屏幕上,以便您可以看到 SQL Django 认为需要什么。它对于检查 Django 将要执行的操作或您的数据库管理员是否需要 SQL 脚本进行更改非常有用。

如果你有兴趣,也可以运行 ;这会检查项目中的任何问题,而无需进行迁移或接触数据库。python manage.py check

现在,migrate再次运行以在数据库中创建这些模型表:

...\> py manage.py migrate
要执行的操作:
应用所有迁移:admin、auth、contenttypes、民意调查、会话
运行迁移:
渲染模型状态...完成
应用 polls.0001_initial...确定

migrate命令获取所有尚未应用的迁移(Django 使用数据库中名为 的特殊表来跟踪应用了哪些迁移django_migrations)并针对您的数据库运行它们 - 本质上,将您对模型所做的更改与数据库。

迁移功能非常强大,可以让您在开发项目时随着时间的推移更改模型,而无需删除数据库或表并创建新的数据库或表 - 它专门用于实时升级数据库,而不会丢失数据。我们将在本教程的后面部分更深入地介绍它们,但现在,请记住进行模型更改的三步指南:

之所以有单独的命令来进行和应用迁移,是因为您将向版本控制系统提交迁移并将它们与您的应用程序一起发布;它们不仅使您的开发变得更容易,而且还可供其他开发人员和生产环境使用。

阅读django-admin 文档以获取有关该manage.py实用程序功能的完整信息。

使用 API

现在,让我们跳进交互式 Python shell 并使用 Django 为您提供的免费 API。要调用 Python shell,请使用以下命令:

...\> py manage.py shell

我们使用它而不是简单地输入“python”,因为manage.py 设置了DJANGO_SETTINGS_MODULE环境变量,它为 Django 提供文件的 Python 导入路径mysite/settings.py

进入 shell 后,探索数据库 API

>>> from polls.models import Choice, Question  # Import the model classes we just wrote.

# No questions are in the system yet.
>>> Question.objects.all()
<QuerySet []>

# Create a new Question.
# Support for time zones is enabled in the default settings file, so
# Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
>>> from django.utils import timezone
>>> q = Question(question_text="What's new?", pub_date=timezone.now())

# Save the object into the database. You have to call save() explicitly.
>>> q.save()

# Now it has an ID.
>>> q.id
1

# Access model field values via Python attributes.
>>> q.question_text
"What's new?"
>>> q.pub_date
datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=datetime.timezone.utc)

# Change values by changing the attributes, then calling save().
>>> q.question_text = "What's up?"
>>> q.save()

# objects.all() displays all the questions in the database.
>>> Question.objects.all()
<QuerySet [<Question: Question object (1)>]>

等一下。不是这个对象的有用表示。让我们通过编辑模型(在文件中) 并向and 添加一个方法来解决这个问题:<Question: Question object (1)>``Question``polls/models.py__str__()Question``Choice

polls/models.py

from django.db import models


class Question(models.Model):
# ...
def __str__(self):
return self.question_text


class 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 timezone


class Question(models.Model):
# ...
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

请注意添加和,分别引用 Python 的标准模块和 Django 中与时区相关的实用程序。如果您不熟悉 Python 中的时区处理,可以在时区支持文档中了解更多信息。import datetime``from django.utils import timezonedatetimedjango.utils.timezone

保存这些更改并再次运行启动新的 Python 交互式 shell :python manage.py shell

>>> from polls.models import Choice, Question

# Make sure our __str__() addition worked.
>>> Question.objects.all()
<QuerySet [<Question: What's up?>]>

# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> Question.objects.filter(id=1)
<QuerySet [<Question: What's up?>]>
>>> Question.objects.filter(question_text__startswith="What")
<QuerySet [<Question: What's up?>]>

# Get the question that was published this year.
>>> from django.utils import timezone
>>> current_year = timezone.now().year
>>> Question.objects.get(pub_date__year=current_year)
<Question: What's up?>

# Request an ID that doesn't exist, this will raise an exception.
>>> Question.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Question matching query does not exist.

# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to Question.objects.get(id=1).
>>> Question.objects.get(pk=1)
<Question: What's up?>

# Make sure our custom method worked.
>>> q = Question.objects.get(pk=1)
>>> q.was_published_recently()
True

# Give the Question a couple of Choices. The create call constructs a new
# Choice object, does the INSERT statement, adds the choice to the set
# of available choices and returns the new Choice object. Django creates
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via the API.
>>> q = Question.objects.get(pk=1)

# Display any choices from the related object set -- none so far.
>>> q.choice_set.all()
<QuerySet []>

# Create three choices.
>>> 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 objects have API access to their related Question objects.
>>> c.question
<Question: What's up?>

# And vice versa: Question objects get access to Choice objects.
>>> q.choice_set.all()
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>
>>> q.choice_set.count()
3

# The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit.
# Find all Choices for any question whose pub_date is in this year
# (reusing the 'current_year' variable we created above).
>>> Choice.objects.filter(question__pub_date__year=current_year)
<QuerySet [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]>

# Let's delete one of the choices. Use delete() for that.
>>> c = q.choice_set.filter(choice_text__startswith="Just hacking")
>>> c.delete()

有关模型关系的更多信息,请参阅访问相关对象。有关如何使用双下划线通过 API 执行字段查找的更多信息,请参阅字段查找。有关数据库 API 的完整详细信息,请参阅我们的数据库 API 参考

Django 管理简介

哲学

为您的员工或客户生成管理网站以添加、更改和删除内容是一项乏味的工作,不需要太多创造力。因此,Django 完全自动创建模型的管理界面。

Django 是在新闻编辑室环境中编写的,“内容发布者”和“公共”站点之间有非常清晰的分离。站点管理员使用该系统添加新闻报道、事件、体育比分等,并将这些内容显示在公共站点上。 Django 解决了为站点管理员创建统一界面来编辑内容的问题。

管理员不适合网站访问者使用。它适用于站点管理员。

创建管理员用户

首先,我们需要创建一个可以登录管理站点的用户。运行以下命令:

...\> py manage.py createsuperuser

输入您想要的用户名并按 Enter 键。

Username: admin

然后系统会提示您输入所需的电子邮件地址:

Email address: admin@example.com

最后一步是输入您的密码。系统会要求您输入两次密码,第二次是对第一次的确认。

Password: **********
Password (again): *********
Superuser created successfully.

启动开发服务器

Django 管理站点默认处于激活状态。让我们启动开发服务器并探索它。

如果服务器没有运行,请像这样启动它:

...\> py manage.py runserver

现在,打开网络浏览器并转到本地域上的“/admin/” - 例如, http://127.0.0.1:8000/admin / 。您应该看到管理员的登录屏幕:

Django 管理员登录屏幕

由于默认情况下翻译是打开的,如果您设置LANGUAGE_CODE,登录屏幕将以给定语言显示(如果 Django 有适当的翻译)。

进入管理站点

现在,尝试使用您在上一步中创建的超级用户帐户登录。您应该看到 Django 管理索引页面:

Django 管理索引页面

您应该看到几种类型的可编辑内容:组和用户。它们django.contrib.auth由 Django 提供的身份验证框架提供。

使民意调查应用程序可在管理员中修改

但是我们的民意调查应用程序在哪里?它不会显示在管理索引页面上。

只需要做一件事:我们需要告诉管理员Question对象有一个管理界面。为此,请打开该polls/admin.py文件,并将其编辑为如下所示:

polls/admin.py

from django.contrib import admin

from .models import Question

admin.site.register(Question)

探索免费的管理功能

现在我们已经注册了Question,Django 知道它应该显示在管理索引页面上:

Django 管理索引页面,现在显示民意调查

点击“问题”。现在您将进入“更改列表”页面来提问。此页面显示数据库中的所有问题,并允许您选择一个来更改它。还有“怎么了?”我们之前创建的问题:

投票更改列表页面

单击“怎么了?”编辑它的问题:

编辑问题对象的表单

这里需要注意的事项:

  • 表单是从Question模型自动生成的。
  • 不同的模型字段类型(DateTimeFieldCharField)对应于适当的 HTML 输入小部件。每种类型的字段都知道如何在 Django 管理中显示自己。
  • 每个人都DateTimeField可以获得免费的 JavaScript 快捷方式。日期有一个“今天”快捷方式和日历弹出窗口,时间有一个“现在”快捷方式和一个方便的弹出窗口,其中列出了常用输入的时间。

页面底部为您提供了几个选项:

  • 保存 – 保存更改并返回到此类对象的更改列表页面。
  • 保存并继续编辑 – 保存更改并重新加载该对象的管理页面。
  • 保存并添加另一个 - 保存更改并加载此类对象的新空白表单。
  • 删除 – 显示删除确认页面。

如果“发布日期”的值与您在教程 1中创建问题的时间不匹配,则可能意味着您忘记为该TIME_ZONE设置设置正确的值。更改它,重新加载页面并检查是否显示正确的值。

通过单击“今天”和“现在”快捷方式更改“发布日期”。然后单击“保存并继续编辑”。然后点击右上角的“历史记录”。您将看到一个页面,其中列出了通过 Django 管理员对此对象所做的所有更改,以及进行更改的人的时间戳和用户名:

问题对象的历史页面