编写你的第一个 Django 应用程序,第2部分
接着上次第1部分开始,现在我们将设置数据库,创建您的第一个模型,并快速获得 介绍 Django 自动生成的管理站点。
一、数据库设置
现在,打开.这是一个普通的 Python 模块,具有 表示 Django 设置的模块级变量。mysite/settings.py
默认情况下,配置使用 SQLite。如果您不熟悉数据库,或者 你只是对尝试 Django 感兴趣,这是最简单的选择。SQLite 是 包含在 Python 中,因此您无需安装任何其他内容来支持您的 数据库。但是,在开始您的第一个实际项目时,您可能希望使用 更具可扩展性的数据库,如PostgreSQL,以避免数据库切换难题 在路上。
如果要使用其他数据库,请安装相应的数据库 绑定并更改“数据库”项中的以下键以匹配数据库
连接 设置:'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 作为数据库,则必须添加其他设置,如 USER
、PASSWORD
和 HOST
。 有关更多详细信息,请参阅数据库
的参考文档。
参考我的数据库配置:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'world', "USER": "root", "PASSWORD": "123456", "HOST": "127.0.0.1", "PORT": "3306", "OPTIONS": {"init_command": "SET default_storage_engine=INNODB",}, } }
二、创建模型
现在我们将定义您的模型 - 本质上是您的数据库布局,使用 其他元数据。
在我们的投票应用程序中,我们将创建两个模型: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 什么 每个字段包含的数据类型。
每个字段
实例的名称(例如 或 ) 是字段的名称,机器友好 格式。您将在 Python 代码中使用此值,您的数据库将使用 它作为列名。(question_text or
pub_date)
您可以使用可选的 Field
第一个位置参数来指定人类可读的名称。那是用的 在 Django 的几个内省部分中,它兼作文档。 如果未提供此字段,Django 将使用机器可读的名称。在此 例如,我们只为 定义了一个人类可读的名称。 对于此模型中的所有其他字段,字段的机器可读名称将 作为其人类可读的名称就足够了。Question.pub_date
某些字段
类具有必需的参数。例如,CharField
要求你给它一个max_length
。这不仅用于 数据库架构,但在验证中,我们很快就会看到。
字段
还可以具有各种可选参数;在 在本例中,我们将votes默认值
设置为 0。
最后,请注意使用外键
定义了关系。这告诉 Django 每个都是 与单个 .Django 支持所有通用数据库 关系:多对一、多对多和一对一。每个Choice
都关联 一个Question 。
三、激活模型
这一小部分模型代码为 Django 提供了大量信息。有了它,Django 能够:
- 为此应用创建数据库架构(语句)。
CREATE TABLE
- 创建用于访问和
Question 和
Choice
对象的 Python 数据库访问 API。
但首先我们需要告诉我们的项目已安装该polls应用程序。
要将应用程序包含在我们的项目中,我们需要编辑 mysite/settings.py 文件,添加对其的引用 INSTALLED_APPS
设置中的配置类。
将 'polls.apps.PollsConfig' 添加到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应用程序。让我们运行另一个命令(记得进入 manage.py 所在目录):
$ python 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改变了事情。
有一个命令将为您运行迁移并管理您的数据库 架构自动 - 这称为迁移
,我们将在 时刻 - 但首先,让我们看看迁移将运行什么 SQL。sqlmigrate
命令采用迁移名称并返回其 SQL:
$ python 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"
- 外键关系由约束显式。不要担心零件;这很能说明问题 PostgreSQL 在事务结束之前不强制执行外键。
FOREIGN KEY
DEFERRABLE
- 它是针对您正在使用的数据库量身定制的,因此特定于数据库的字段类型 例如(MySQL),(PostgreSQL)或(SQLite) 会自动为您处理。引用字段名称也是如此 – 例如,使用双引号或单引号。
auto_increment
bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY
integer primary key autoincrement
sqlmigrate
命令实际上不会在 数据库 - 相反,它会将其打印到屏幕上,以便您可以看到什么 SQL Django认为是必需的。它对于检查 Django 将要做什么很有用 执行,或者如果您有需要 SQL 脚本的数据库管理员 变化。
如果你有兴趣,你也可以运行python manage.py 检查
;这将检查 您的项目,无需进行迁移或接触数据库。
现在,再次运行 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
迁移命令将执行所有尚未进行的迁移
应用(Django 使用您的特殊表跟踪哪些应用了 数据库称为 ) 并针对您的数据库运行它们 - 实质上,将您对模型所做的更改与架构同步 在数据库中。django_migrations
迁移功能非常强大,可让您随时间更改模型,因为 开发您的项目,而无需删除您的数据库或表,以及 制作新的 - 它专门实时升级您的数据库,无需 丢失数据。我们将在本教程的后面部分更深入地介绍它们, 但现在,请记住进行模型更改的三步指南:
- 更改模型(在 中)。
models.py
- 运行
python manage.py makemigrations
来创建 这些更改的迁移 - 运行
python manage.py 迁移
以将这些更改应用于 数据库。
有单独的命令进行和应用迁移的原因是 因为您将向版本控制系统提交迁移并交付它们 与您的应用程序一起使用;它们不仅使您的开发更容易,而且还 可供其他开发人员和生产环境使用。
阅读 django 管理员文档了解完整内容 有关manage.py实用程序可以执行的操作的信息。
四、使用接口
现在,让我们跳入交互式 Python shell,并使用免费的 API Django 给你。要调用 Python shell,请使用以下命令:
$ python manage.py shell
我们使用它而不是简单地键入“python”,因为设置DJANGO_SETTINGS_MODULE
环境变量,这给出了 Django 文件的 Python 导入路径到 manage.py
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)>]><Question: Question object (1)>
看不懂对象数据. 修改polls/models.py文件,对Question
andChoice
2个对象模型,都添加1个方法__str__()
:
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): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField("date published") def __str__(self): return self.question_text #自定义方法 def 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
保存这些更改,然后通过再次运行来启动新的 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.