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

本教程从以下位置开始 Tutorial 1 停下来了。我们将设置数据库,创建您的第一个模型,并快速介绍Django自动生成的管理站点。

从哪里获得帮助:

如果您在阅读本教程时遇到困难,请访问 Getting Help 部分的常见问题解答。

数据库设置

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

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

如果您希望使用其他数据库,请参阅 details to customize and get your database running

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

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

默认情况下, INSTALLED_APPS 包含以下应用程序,所有这些应用程序均随Django提供:

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

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

$ python manage.py migrate
...\> 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创建的表。

对于极简主义者来说

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

创建模型

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

哲理

模型是关于您的数据的唯一、明确的信息源。它包含要存储的数据的基本字段和行为。Django遵循着 DRY Principle 。目标是在一个地方定义您的数据模型,并自动从中派生内容。

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

在我们的民意调查应用程序中,我们将创建两个模型: QuestionChoice 。一个 Question 有一个问题和一个发布日期。一 Choice 有两个字段:选择文本和投票计数。每个 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代码中使用此值,并且您的数据库将使用它作为列名。

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

一些人 Field 类需要参数。 CharField 例如,需要您给它一个 max_length .正如我们很快就会看到的那样,它不仅在数据库模式中使用,而且在验证中使用。

A Field 还可以有各种可选参数;在这种情况下,我们设置了 default 的价值 votes 设置为0。

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

激活模型

这一小部分模型代码为Django提供了很多信息。有了它,Django能够:

  • 创建数据库模式 (CREATE TABLE 声明)对此应用程序。

  • 创建Python数据库访问API用于访问 QuestionChoice 物体。

但首先我们需要告诉我们的项目 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",
]

现在姜戈知道要包括 polls app。让我们运行另一个命令:

$ python manage.py makemigrations polls
...\> py manage.py makemigrations polls

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

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

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

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

有一个命令可以为您运行迁移并自动管理您的数据库模式-称为 migrate ,我们稍后将讨论它-但首先,让我们看看迁移将运行什么SQL。的 sqlmigrate 命令获取迁移名称并返回其SQL:

$ python manage.py sqlmigrate polls 0001
...\> py manage.py sqlmigrate polls 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 )以及模特的别名-- questionchoice . (You可以覆盖此行为。)

  • 主密钥(ID)会自动添加。(You也可以覆盖这一点。)

  • 按照惯例,姜戈补充 "_id" 到外部关键字字段名称。(Yes,您也可以覆盖此功能。)

  • 外国钥匙关系由一位明确表示 FOREIGN KEY 约束。别担心 DEFERRABLE 部分;它告诉PostgreSQL在事务结束之前不要强制执行外部密钥。

  • 它是为您正在使用的数据库量身定做的,因此特定于数据库的字段类型,如 auto_increment (MySQL), bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (PostgreSQL),或 integer primary key autoincrement (SQLite)是自动为您处理的。对于字段名称的引号也是如此--例如,使用双引号或单引号。

  • 这个 sqlmigrate 命令实际上不会在您的数据库上运行迁移-相反,它会将其打印到屏幕上,以便您可以查看SQL Django认为需要的内容。它对于检查Django要做什么或者您是否有需要SQL脚本进行更改的数据库管理员很有用。

如果您感兴趣,也可以跑步 python manage.py check ;这将检查您的项目中的任何问题,而无需进行迁移或触摸数据库。

现在,快跑 migrate 再次在数据库中创建这些模型表:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Rendering model states... DONE
  Applying polls.0001_initial... OK
...\> py manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
  Rendering model states... DONE
  Applying polls.0001_initial... OK

这个 migrate 命令获取所有尚未应用的迁移(Django使用数据库中名为 django_migrations )并在您的数据库中运行它们-本质上是将您对模型所做的更改与数据库中的模式同步。

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

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

请阅读 django-admin documentation 有关什么的完整信息 manage.py 实用程序可以做。

使用API

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

$ python manage.py shell
...\> py manage.py shell

我们使用这个而不是简单地输入“python”,因为 manage.py 设置 DJANGO_SETTINGS_MODULE 环境变量,它为Django提供了Python导入路径 mysite/settings.py 文件.默认情况下 shell 命令自动从您的导入模型 INSTALLED_APPS .

一旦您进入Shell,就可以探索 database API

# 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.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)>]>

等一下 <Question: Question object (1)> 并不是这个对象的有用表示。让我们通过编辑 Question 模型(在 polls/models.py 文件)并添加 __str__() 控制电源的 QuestionChoice

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)

请注意添加 import datetimefrom django.utils import timezone ,参考Python的标准 datetime 模块和Django的时区相关实用程序 django.utils.timezone ,分别。如果您不熟悉Python中的时区处理,您可以在 time zone support docs

保存这些更改并通过运行以下命令启动新的Python交互Shell python manage.py shell 再说一遍:

# 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 (defined as "choice_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()

有关模型关系的更多信息,请参阅 Accessing related objects .有关如何使用双强调线通过API执行字段查找的详细信息,请参阅 Field lookups .有关数据库API的完整详细信息,请参阅我们的 Database API reference

介绍Django管理员

哲理

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

Django是在新闻编辑室环境中撰写的,“内容出版商”和“公共”网站之间有着非常明显的区分。网站管理员使用该系统添加新闻报道、事件、体育比分等,并且该内容显示在公共网站上。Django解决了为网站管理员创建统一界面来编辑内容的问题。

该管理员无意供网站访问者使用。这是为网站经理准备的。

创建管理员用户

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

$ python manage.py createsuperuser
...\> py manage.py createsuperuser

输入您所需的用户名并按输入键。

Username: admin

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

Email address: admin@example.com

最后一步是输入您的密码。您将被要求输入密码两次,第二次作为第一次的确认。

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

启动开发服务器

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

如果服务器未运行,请按如下方式启动:

$ python manage.py runserver
...\> py manage.py runserver

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

Django管理登录屏幕

自.以来 translation 如果您设置,则默认打开 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管理索引页面,现在显示民意调查

单击“问题”。现在,您位于“更改列表”页面以获取问题。此页面显示数据库中的所有问题,并允许您选择一个来更改它。有“What ' s up?“我们之前提出的问题:

民意调查更改列表页面

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

问题对象编辑表格

这里需要注意的事项:

  • 该表格是从 Question 模特。

  • 不同的模型字段类型 (DateTimeFieldCharField )对应于适当的HTML输入小部件。每种类型的字段都知道如何在Django管理中显示自己。

  • 每个 DateTimeField 获得免费的JavaScript快捷方式。日期有一个“今天”快捷方式和日历弹出窗口,时间有一个“现在”快捷方式和一个方便的弹出窗口,列出了常用输入的时间。

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

  • 保存--卸载更改并返回到此类型对象的更改列表页面。

  • 保存并继续编辑--收件箱更改并重新加载此对象的管理页面。

  • 保存并添加另一个--收件箱更改并加载此类型对象的新空白表单。

  • 删除--显示删除确认页面。

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

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

问题对象的历史页面

当您熟悉模型API并熟悉管理网站后,请阅读 part 3 of this tutorial 了解如何向我们的民意调查应用程序添加更多视图。