《Django》入门 Notes(下)
《Django》入门 Notes(下)
@Seymour0314 来源官方文档https://docs.djangoproject.com/zh-hans/4.2/intro/
本文是Django 后端技术初级入门教程。
编程语言:Python
第 6 部分
本教程从 教程第 5 部分结束的地方开始。
我们已经建立了一个经过测试的网络投票应用程序,现在我们将添加一个样式表和一个图像。
除了服务端生成的 HTML 以外,网络应用通常需要一些额外的文件——比如图片,脚本和样式表——来帮助渲染网络页面。
在 Django 中,我们把这些文件统称为“静态文件”。
对于小项目来说,这个问题没什么大不了的,因为你可以把这些静态文件随便放在哪,只要服务程序能够找到它们就行。然而在大项目——特别是由好几个应用组成的大项目——中,处理不同应用所需要的静态文件的工作就显得有点麻烦了。
这就是
django.contrib.staticfiles
存在的意义:它将各个应用的静态文件(和一些你指明的目录里的文件)统一收集起来,
这样一来,在生产环境中,这些文件就会集中在一个便于分发的地方。
6.1 自定义 应用 的界面和风格
-
首先,在你的
polls
目录下创建一个名为static
的目录。-
Django 将在该目录下查找静态文件,这种方式和 Diango 在
polls/templates/
目录下查找 template 的方式类似。 -
Django 的
STATICFILES_FINDERS
设置包含了一系列的查找器,它们知道去哪里找到 static 文件。-
AppDirectoriesFinder
是默认查找器中的一个,它会在每个
INSTALLED_APPS
中指定的应用的子文件中寻找名称为static
的特定文件夹,就像我们在
polls
中刚创建的那个一样。管理后台采用相同的目录结构管理它的静态文件。
-
-
-
在你刚创建的
static
文件夹中创建一个名为polls
的文件夹,再在polls
文件夹中创建一个名为style.css
的文件。换句话说,你的样式表路径应是
polls/static/polls/style.css
。因为
AppDirectoriesFinder
的存在,你可以在 Django 中以
polls/style.css
的形式引用此文件,类似你引用模板路径的方式。- 静态文件命名空间
虽然我们 可以 像管理模板文件一样,把 static 文件直接放入
polls/static
(而不是创建另一个名为polls
的子文件夹),不过这实际上是一个很蠢的做法。Django 只会使用第一个找到的静态文件。如果你在 其它 应用中有一个相同名字的静态文件,Django 将无法区分它们。我们需要指引 Django 选择正确的静态文件,而最好的方式就是把它们放入各自的 命名空间 。也就是把这些静态文件放入 另一个 与应用名相同的目录中。 -
将以下代码放入样式表:
polls/static/polls/style.css
1
2
3li a {
color: green;
} -
下一步,在 对应的的文件头添加以下内容:
polls/templates/polls/index.html
1
2
3{% load static %}
<link rel="stylesheet" href="{% static 'polls/style.css' %}">{% static %}
模板标签会生成静态文件的绝对路径。这就是你开发所需要做的所有事情了。
-
启动服务器(如果它正在运行中,重新启动一次):
1
...\> py manage.py runserver
重新载入
http://localhost:8000/polls/
,你会发现有问题的链接是绿色的 (这是 Django 自己的问题标注方式),这意味着你追加的样式表起作用了。
6.2 添加一个背景图
接下来,我们将为图像创建一个子目录。
-
在
polls/static/polls/
目录中创建images
子目录。在此目录中,添加您想用作背景的任何图像文件。
出于本教程的目的,我们使用了一个名为“background.png”的文件,
它的完整路径为“polls/static/polls/images/background.png”。
注意:我这里测试使用的是jpg格式!
-
然后,在样式表中添加对图像的引用:
polls/static/polls/style.css
1
2
3body {
background: white url("images/background.png") no-repeat;
}浏览器重载
http://localhost:8000/polls/
,你将在屏幕的左上角见到这张背景图。警告
{% static %}
模板标签在静态文件(例如样式表)中是不可用的,因为它们不是由 Django 生成的。你应该始终使用 相对路径 在你的静态文件之间相互引用,
因为这样你可以更改
STATIC_URL
(由static
模板标签使用来生成 URL),而无需修改大量的静态文件。
这些只是 基础 。
更多关于设置和框架的资料,参考 静态文件解惑 和 静态文件指南。
部署静态文件 介绍了如何在真实服务器上使用静态文件。
当你熟悉静态文件后,阅读 此教程的第 7 部分 来学习如何自定义 Django 自动生成后台网页的过程。
第 7 部分
本教程从 教程第 6 部分 结束的地方开始。
我们继续修改在线投票应用,这次我们专注于自定义我们在 教程第 2 部分初见过的 Django 自动生成后台的过程。
7.1 自定义后台表单
通过
admin.site.register(Question)
注册Question
模型,Django 能够构建一个默认的表单用于展示。通常来说,你期望能自定义表单的外观和工作方式。你可以在注册模型时将这些设置告诉 Django。
-
让我们通过重排列表单上的字段来看看它是怎么工作的。
用以下内容替换
admin.site.register(Question)
:polls/admin.py
1
2
3
4
5
6
7
8
9
10from django.contrib import admin
from .models import Question
class QuestionAdmin(admin.ModelAdmin):
fields = ["pub_date", "question_text"]
admin.site.register(Question, QuestionAdmin)更改对比:
-
你需要遵循以下流程:
创建一个模型后台类,
接着将其作为第二个参数传给
admin.site.register()
——在你需要修改模型的后台管理选项时这么做。以上修改使得 “Publication date” 字段显示在 “Question” 字段之前:
这在只有两个字段时显得没啥卵用,
但对于拥有数十个字段的表单来说,为表单选择一个直观的排序方法就显得你的针很细了。
说到拥有数十个字段的表单,你可能更期望将表单分为几个字段集:
polls/admin.py
1
2
3
4
5
6
7
8
9
10
11
12
13from django.contrib import admin
from .models import Question
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {"fields": ["question_text"]}),
("Date information", {"fields": ["pub_date"]}),
]
admin.site.register(Question, QuestionAdmin)fieldsets
元组中的第一个元素是字段集的标题。以下是我们的表单现在的样子:效果:
7.2 添加关联的对象
-
好了,现在我们有了投票的后台页。不过,一个
Question
有多个Choice
,但后台页却没有显示多个选项。有两个方法可以解决这个问题。
-
(方法一)第一个就是仿照我们向后台注册
Question
一样注册Choice
:polls/admin.py
1
2
3
4
5
6from django.contrib import admin
from .models import Choice, Question
# ...
admin.site.register(Choice)现在 “Choices” 在 Django 后台页中是一个可用的选项了。
“添加选项”的表单看起来像这样:
在这个表单中,“Question” 字段是一个包含数据库中所有投票的选择框。
Django 知道要将
ForeignKey
在后台中以选择框<select>
的形式展示。此时,我们只有一个投票。
还请注意“问题”旁边的“添加另一个问题”链接。
每个与另一个具有
ForeignKey
关系的对象都可以免费获得此链接。当你点击“添加另一个问题”时,你会看到一个带有“添加问题”表单的弹出窗口。如果你在该窗口中添加问题并点击“保存”,Django会将问题保存到数据库中,并将其动态添加为你正在查看的“添加选项”表单上的选定选项。
不过,这是一种很低效地添加“选项”的方法。更好的办法是在你创建“投票”对象时直接添加好几个选项。让我们实现它。
-
(方法二)移除调用
register()
注册Choice
模型的代码。随后,像这样修改
Question
的注册代码:polls/admin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19from django.contrib import admin
from .models import Choice, Question
class ChoiceInline(admin.StackedInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {"fields": ["question_text"]}),
("Date information", {"fields": ["pub_date"], "classes": ["collapse"]}),
]
inlines = [ChoiceInline]
admin.site.register(Question, QuestionAdmin)这会告诉 Django:“
Choice
对象要在Question
后台页面编辑。默认提供 3 个足够的选项字段。”加载“添加投票”页面来看看它长啥样:
它看起来像这样:
有三个关联的选项插槽——由
extra
定义,且每次你返回任意已创建的对象的“修改”页面时,你会见到三个新的插槽。在三个插槽的末端,你会看到一个“添加新选项”的按钮。
如果你单击它,一个新的插槽会被添加。
如果你想移除已有的插槽,可以点击插槽右上角的X。以下图片展示了一个已添加的插槽:
-
不过,仍然有点小问题。
它占据了大量的屏幕区域来显示所有关联的
Choice
对象的字段。对于这个问题,Django 提供了一种表格式的单行显示关联对象的方法。
要使用它,只需按如下形式修改
ChoiceInline
申明:polls/admin.py
1
2class ChoiceInline(admin.TabularInline):
...通过
TabularInline
(替代StackedInline
),关联对象以一种表格式的方式展示,显得更加紧凑:请注意,有一个额外的“删除?”列,允许删除使用“添加另一个选项”按钮添加的行和已保存的行。
7.3 自定义后台更改列表
-
现在投票的后台页看起来很不错,让我们对“更改列表”页面进行一些调整——改成一个能展示系统中所有投票的页面。
以下是它此时的外观:
默认情况下,Django 显示每个对象的
str()
返回的值。但有时如果我们能够显示单个字段,它会更有帮助。 -
为此,使用
list_display
后台选项,它是一个包含要显示的字段名的元组,在更改列表页中以列的形式展示这个对象:另外,让我们把 教程第 2 部分中的
was_published_recently()
方法也加上:polls/admin.py
1
2
3class QuestionAdmin(admin.ModelAdmin):
# ...
list_display = ["question_text", "pub_date", "was_published_recently"]现在修改投票的列表页看起来像这样:
你可以点击列标题来对这些行进行排序——除了
was_published_recently
这个列,因为没有实现排序方法。顺便看下这个列的标题
was_published_recently
,默认就是方法名(用空格替换下划线),该列的每行都以字符串形式展示出处。 -
你可以通过在该方法上(在
polls/models.py
中)使用display()
装饰器来改进,如下图所示:polls/models.py
1
2
3
4
5
6
7
8
9
10
11
12
13from django.contrib import admin
class Question(models.Model):
# ...
)
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now更多关于可通过装饰器设置的属性的信息,请参见
list_display
。 -
再次编辑文件
polls/admin.py
,优化Question
变更页:过滤器,使用list_filter
。将以下代码添加至
QuestionAdmin
:polls/admin.py
1
list_filter = ["pub_date"]
这样做添加了一个“过滤器”侧边栏,允许人们以
pub_date
字段来过滤列表:展示的过滤器类型取决你你要过滤的字段的类型。
因为
pub_date
是类DateTimeField
,Django 知道要提供哪个过滤器:“任意时间”,“今天”,“过去7天”,“这个月”和“今年”。 -
这已经弄的很好了。让我们再扩充些功能:
1
search_fields = ["question_text"]
在列表的顶部增加一个搜索框。当输入待搜项时,Django 将搜索
question_text
字段。你可以使用任意多的字段——由于后台使用
LIKE
来查询数据,将待搜索的字段数限制为一个不会出问题大小,会便于数据库进行查询操作。 -
现在是给你的修改列表页增加分页功能的好时机。
默认每页显示 100 项。
7.4 自定义后台界面和风格
在每个后台页顶部显示“Django 管理员”显得很滑稽。这只是一串占位文本。
不过,你可以通过 Django 的模板系统来修改。
Django 的后台由自己驱动,且它的交互接口采用 Django 自己的模板系统。
自定义你的 工程的 模板
-
在你的工程目录(指包含
manage.py
的那个文件夹)内创建一个名为templates
的目录。模板可放在你系统中任何 Django 能找到的位置。(谁启动了 Django,Django 就以他的用户身份运行。)
不过,把你的模板放在工程内会带来很大便利,推荐你这样做。
-
打开你的设置文件(
mysite/settings.py
,牢记),在TEMPLATES
设置中添加DIRS
选项:mysite/settings.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]DIRS
是一个包含多个系统目录的文件列表,用于在载入 Django 模板时使用,是一个待搜索路径。组织模板
就像静态文件一样,我们 可以 把所有的模板文件放在一个大模板目录内,这样它也能工作的很好。
但是,属于特定应用的模板文件最好放在应用所属的模板目录(例如
polls/templates
),而不是工程的模板目录(templates
)。我们会在 创建可复用的应用教程 中讨论 为什么 我们要这样做。Django 的源文件在哪里?
如果你不知道 Django 源码在你系统的哪个位置,运行以下命令:
1
...\> py -c "import django; print(django.__path__)"
-
接着,用你网页站点的名字编辑替换文件内的
{{ site_header|default:_('Django administration') }}
(包含大括号)。完成后,你应该看到如下代码:
1
2
3{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
{% endblock %}我们会用这个方法来教你复写模板。
在一个实际工程中,你可能更期望使用
django.contrib.admin.AdminSite.site_header
来进行简单的定制。这个模板文件包含很多类似
{% block branding %}
和{{ title }}
的文本。`