本教程从以下位置开始 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作为数据库,则需要其他设置,例如 USER
, PASSWORD
和 HOST
必须添加。有关更多详细信息,请参阅参考文档 DATABASES
.
对于sqlite以外的数据库
如果您使用的是除sqlite之外的数据库,请确保此时已经创建了一个数据库。在数据库的交互式提示中,使用“创建数据库`名称;
”执行此操作。
还要确保在 mysite/settings.py
具有“创建数据库”权限。这允许自动创建 test database 这将在后面的教程中需要。
如果您使用的是sqlite,则不需要事先创建任何内容—数据库文件将在需要时自动创建。
在编辑时 mysite/settings.py
,集合 TIME_ZONE
到你的时区。
另外,请注意 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
--管理静态文件的框架。
默认情况下,这些应用程序是为了方便常见情况而包含的。
不过,其中一些应用程序至少使用一个数据库表,因此我们需要先在数据库中创建这些表,然后才能使用它们。为此,请运行以下命令:
$ 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可以滚动更新数据库模式以匹配当前模型的历史。
在我们的投票应用程序中,我们将创建两个模型: Question
和 Choice
. 一 Question
有问题和发布日期。一 Choice
有两个字段:选项文本和投票计数。各 Choice
与 Question
.
这些概念由Python类表示。编辑 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_text
或 pub_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 Question
和 Choice
对象。
但首先我们需要告诉我们的项目 polls
已安装应用程序。
原理
Django应用程序是“可插入的”:您可以在多个项目中使用一个应用程序,并且可以分发应用程序,因为它们不必绑定到给定的Django安装。
要在我们的项目中包含该应用程序,我们需要在 INSTALLED_APPS
设置。这个 PollsConfig
类在 polls/apps.py
文件,所以它的虚线路径是 'polls.apps.PollsConfig'
. 编辑 mysite/settings.py
文件并将该虚线路径添加到 INSTALLED_APPS
设置。看起来像这样:
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
)模型的小写名称-- question
和 choice
. (可以覆盖此行为。)
主键(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
)并针对您的数据库运行它们——本质上,是将您对模型所做的更改与数据库中的模式同步。
迁移功能非常强大,可以让您在开发项目时随时更改模型,而无需删除数据库或表并创建新的模型—它专门用于实时升级数据库,而不会丢失数据。在本教程的后面部分,我们将更深入地介绍它们,但现在,请记住进行模型更改的三步指南:
更改您的模型(在 models.py
)
运行 python manage.py makemigrations
为这些更改创建迁移
运行 python manage.py migrate
将这些更改应用到数据库。
之所以有单独的命令来进行和应用迁移,是因为您将把迁移提交到您的版本控制系统,并将它们与应用程序一起发送;它们不仅使您的开发更容易,而且还可供其他开发人员和生产中使用。
阅读 django-admin documentation 有关 manage.py
公用事业可以做到。
现在,让我们跳到交互式的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__()
两种方法 Question
和 Choice
:
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的自动生成的管理中被使用。
我们还可以向该模型添加一个自定义方法:
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 datetime
和 from 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解决了为站点管理员创建统一的界面来编辑内容的问题。
管理员不打算被网站访问者使用。这是给现场经理的。
首先,我们需要创建一个可以登录到管理站点的用户。运行以下命令:
$ 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/.您应该会看到管理员的登录屏幕:
自从 translation 默认情况下处于启用状态,如果设置 LANGUAGE_CODE
,则登录屏幕将以给定的语言显示(如果Django有适当的翻译)。
现在,尝试使用在上一步中创建的超级用户帐户登录。您应该看到django管理索引页面:
您应该看到一些类型的可编辑内容:组和用户。它们由提供 django.contrib.auth
,Django提供的身份验证框架。
但是我们的投票程序呢?它不会显示在管理索引页上。
还有一件事要做:我们需要告诉管理员 Question
对象具有管理界面。要执行此操作,请打开 polls/admin.py
文件,并将其编辑为如下所示:
from django.contrib import admin
from .models import Question
admin.site.register(Question)
现在我们已经注册了 Question
,Django知道它应该显示在管理索引页上:
点击“问题”。现在,您可以在“更改列表”页面上查看问题。此页面显示数据库中的所有问题,并允许您选择一个问题进行更改。有“怎么了?”我们之前创建的问题:
点击“怎么了?”编辑问题:
这里需要注意的事项:
表单自动从 Question
模型。
不同的模型字段类型 (DateTimeField
, CharField
)对应于适当的HTML输入小部件。每种类型的字段都知道如何在django管理中显示自己。
各 DateTimeField
获取免费的javascript快捷方式。日期得到一个“今天”快捷方式和日历弹出窗口,时间得到一个“现在”快捷方式和一个方便的弹出窗口,其中列出了通常输入的时间。
页面底部提供了几个选项:
save——保存更改并返回此类型对象的更改列表页。
保存并继续编辑--保存更改并重新加载此对象的管理页。
保存并添加另一个——保存更改并为此类型的对象加载一个新的空白表单。
删除——显示删除确认页面。
如果“发布日期”的值与在中创建问题的时间不匹配 Tutorial 1 ,这可能意味着您忘记为 TIME_ZONE
设置。更改它,重新加载页面并检查是否显示正确的值。
通过单击“今日”和“现在”快捷方式更改“发布日期”。然后单击“保存并继续编辑”。然后单击右上角的“历史记录”。您将看到一个页面,其中列出了通过django管理员对此对象所做的所有更改,以及更改者的时间戳和用户名:
当您熟悉模型API并熟悉管理站点时,请阅读 part 3 of this tutorial 了解如何向我们的投票应用程序添加更多视图。
12月 18, 2023