编写第一个django应用程序,第2部分

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

从何处获得帮助:

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

数据库设置

现在,打开 mysite/settings.py . 它是一个普通的python模块,模块级变量表示django设置。

默认情况下,配置使用sqlite。如果你对数据库不熟悉,或者只是对Django感兴趣,这是最简单的选择。python中包含了sqlite,所以您不需要安装任何其他东西来支持您的数据库。然而,当您开始第一个真正的项目时,您可能希望使用一个更可扩展的数据库,比如PostgreSQL,以避免数据库切换带来的麻烦。

如果要使用其他数据库,请安装相应的 database bindings 并在 DATABASES 'default' 与数据库连接设置匹配的项:

  • ENGINE ——要么 'django.db.backends.sqlite3''django.db.backends.postgresql''django.db.backends.mysql''django.db.backends.oracle' . 其他后端是 also available .

  • NAME --数据库的名称。如果您使用的是sqlite,那么数据库将是您计算机上的一个文件;在这种情况下, NAME 应该是该文件的完整绝对路径,包括文件名。默认值, BASE_DIR / 'db.sqlite3' ,将文件存储在项目目录中。

如果不使用sqlite作为数据库,则需要其他设置,例如 USERPASSWORDHOST 必须添加。有关更多详细信息,请参阅参考文档 DATABASES .

对于sqlite以外的数据库

如果您使用的是除sqlite之外的数据库,请确保此时已经创建了一个数据库。在数据库的交互式提示中,使用“创建数据库`名称;”执行此操作。

还要确保在 mysite/settings.py 具有“创建数据库”权限。这允许自动创建 test database 这将在后面的教程中需要。

如果您使用的是sqlite,则不需要事先创建任何内容—数据库文件将在需要时自动创建。

在编辑时 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 。目标是在一个地方定义您的数据模型,并自动从中派生内容。

这包括迁移——例如,与RubyonRails不同,迁移完全源于您的模型文件,并且本质上是Django可以滚动更新数据库模式以匹配当前模型的历史。

在我们的投票应用程序中,我们将创建两个模型: QuestionChoice . 一 Question 有问题和发布日期。一 Choice 有两个字段:选项文本和投票计数。各 ChoiceQuestion .

这些概念由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 . 告诉 Django 每个人 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",
]

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

$ 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您对您的模型进行了一些更改(在本例中,您对新模型进行了更改),并且您希望将更改存储为 迁移 .

迁移是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 . (可以覆盖此行为。)

  • 主键(ID)将自动添加。(您也可以覆盖它。)

  • 根据惯例,Django附录 "_id" 到外键字段名。(是的,您也可以覆盖它。)

  • 外键关系由 FOREIGN KEY 约束。别担心 DEFERRABLE 它告诉PostgreSQL在事务结束之前不要强制执行外键。

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

  • 这个 sqlmigrate 命令并不实际在数据库上运行迁移,而是将其打印到屏幕上,这样您就可以看到SQLDjango认为需要什么。它对于检查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提供了 mysite/settings.py 文件。

一旦您进入Shell,就可以探索 database 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)>]>

等一下。 <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 再说一遍:

>>> 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()

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

Django管理员简介

原理

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

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

管理员不打算被网站访问者使用。这是给现场经理的。

创建管理用户

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

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

输入所需的用户名,然后按Enter。

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管理索引页,现在显示投票

点击“问题”。现在,您可以在“更改列表”页面上查看问题。此页面显示数据库中的所有问题,并允许您选择一个问题进行更改。有“怎么了?”我们之前创建的问题:

投票更改列表页面

点击“怎么了?”编辑问题:

编辑问题对象的表单

这里需要注意的事项:

  • 表单自动从 Question 模型。

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

  • DateTimeField 获取免费的javascript快捷方式。日期得到一个“今天”快捷方式和日历弹出窗口,时间得到一个“现在”快捷方式和一个方便的弹出窗口,其中列出了通常输入的时间。

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

  • save——保存更改并返回此类型对象的更改列表页。

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

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

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

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

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

问题对象的历史记录页面

当您熟悉模型API并熟悉管理站点时,请阅读 part 3 of this tutorial 了解如何向我们的投票应用程序添加更多视图。