Django从入门到实战:编写你的第一个 Django 应用(7)

30 篇文章 8 订阅
9 篇文章 4 订阅

上篇博客我们熟悉了静态文件的应用。我依然在周三这一天。

现在我们继续修改在线投票应用,这次我们专注于自定义我们在第二篇博客中初见过的 Django 自动生成后台的过程。

 

自定义后台表单

之前我们通过 admin.site.register(Question) 注册 Question 模型,Django 能够构建一个默认的表单用于展示。

通常来说,你期望能自定义表单的外观和工作方式。你可以在注册模型时将这些设置告诉 Django。

让我们通过重排列表单上的字段来看看它是怎么工作的。用以下内容替换 admin.site.register(Question)

# polls/admin.py

from 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" 字段之前:

Fields have been reordered

这在只有两个字段时显得没啥卵用,但对于拥有数十个字段的表单来说,为表单选择一个直观的排序方法就显得有用了。

说到拥有数十个字段的表单,你可能更期望将表单分为几个字段集:

# polls/admin.py

from 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元组中的第一个元素是字段集的标题。以下是我们的表单现在的样子:

Form has fieldsets now

添加关联的对象

好了,现在我们有了投票的后台页。不过,一个 Question 有多个 Choice,但后台页却没有显示多个选项。

有两个方法可以解决这个问题。第一个就是仿照我们向后台注册 Question 一样注册 Choice 。这很简单:

# polls/admin.py
from django.contrib import admin

from .models import Choice, Question
# ...
admin.site.register(Choice)

现在 "Choices" 在 Django 后台页中是一个可用的选项了。“添加选项”的表单看起来像这样:

Choice admin page

在这个表单中,"Question" 字段是一个包含数据库中所有投票的选择框。Django 知道要将ForeignKey在后台中以选择框 <select> 的形式展示。此时,我们只有一个投票。

同时也注意下 "Question" 旁边的“添加”按钮。每个使用 ForeignKey 关联到另一个对象的对象会自动获得这个功能。当你点击“添加”按钮时,你会见到一个包含“添加投票”的表单。如果你在这个弹出框中添加了一个投票,并点击了“保存”,Django 会将其保存至数据库,并动态地在你正在查看的“添加选项”表单中选中它。

不过,这是一种很低效地添加“选项”的方法。

 

更好的办法是在你创建“投票”对象时直接添加好几个选项。

首先,移除调用 register() 注册 Choice 模型的代码。随后,像这样修改 Question 的注册代码:

# polls/admin.py

from 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 个足够的选项字段。”

加载“添加投票”页面来看看它长啥样:

Add question page now has choices on it

它看起来像这样:有三个关联的选项插槽——由 extra 定义,且每次你返回任意已创建的对象的“修改”页面时,你会见到三个新的插槽。

在三个插槽的末端,你会看到一个“添加新选项”的按钮。如果你单击它,一个新的插槽会被添加。如果你想移除已有的插槽,可以点击插槽右上角的X。注意,你不能移除原始的 3 个插槽。以下图片展示了一个已添加的插槽:

Additional slot added dynamically

不过,仍然有点小问题。它占据了大量的屏幕区域来显示所有关联的 Choice 对象的字段。对于这个问题,Django 提供了一种表格式的单行显示关联对象的方法。你只需按如下形式修改 ChoiceInline 申明:

# polls/admin.py

class ChoiceInline(admin.TabularInline):
    #...

通过 TabularInline(替代StackedInline ),关联对象以一种表格式的方式展示,显得更加紧凑:

Add question page now has more compact choices

注意这里有一个额外的“删除?”列,这允许移除通过“添加新选项”按钮添加的,或是已被保存的行。

 

自定义后台更改列表

现在投票的后台页看起来很不错,让我们对“更改列表”页面进行一些调整——改成一个能展示系统中所有投票的页面。

以下是它此时的外观:

Polls change list page

默认情况下,Django 显示每个对象的 str() 返回的值。但有时如果我们能够显示单个字段,它会更有帮助。

为此,使用 list_display 后台选项,它是一个包含要显示的字段名的元组,在更改列表页中以列的形式展示这个对象:

# polls/admin.py

class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question_text', 'pub_date')

为了更好用,让我们也包含 第二篇博客 中的 was_published_recently() 方法:

# polls/admin.py

class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question_text', 'pub_date', 'was_published_recently')

现在修改投票的列表页看起来像这样:

Polls change list page, updated

你可以点击列标题来对这些行进行排序——除了 was_published_recently 这个列,因为没有实现排序方法。

顺便看下这个列的标题 was_published_recently,默认就是方法名(用空格替换下划线),该列的每行都以字符串形式展示出处。

你可以通过给这个方法(在 polls/models.py 中)一些属性来达到优化的目的,像这样:

# polls/models.py

class Question(models.Model):
    # ...
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'

再次编辑文件 polls/admin.py,优化 Question 修改页——使用过滤器,list_filter。将以下代码添加至 QuestionAdmin

list_filter = ['pub_date']

这样做添加了一个“过滤器”侧边栏,允许人们以 pub_date 字段来过滤列表:

Polls change list page, updated

展示的过滤器类型取决你你要过滤的字段的类型。因为 pub_date 是类 DateTimeField,Django 知道要提供哪个过滤器:“任意时间”,“今天”,“过去7天”,“这个月”和“今年”。

这已经弄的很好了。让我们再扩充些功能:

search_fields = ['question_text']

在列表的顶部增加一个搜索框。当输入待搜项时,Django 将搜索 question_text 字段。你可以使用任意多的字段——由于后台使用 LIKE 来查询数据,将待搜索的字段数限制为一个不会出问题大小,会便于数据库进行查询操作。

现在默认分页功能中每页显示 100 项。

 

自定义后台界面和风格

在每个后台页顶部显示“Django 管理员”显得很滑稽。这只是一串占位文本。

不过,这可以通过 Django 的模板系统很方便的修改。Django 的后台由自己驱动,且它的交互接口采用 Django 自己的模板系统。

1. 自定义你的项目的模板

在你的项目目录(指包含 manage.py 的那个文件夹)内创建一个名为 templates 的目录。(谁启动了 Django,Django 就以他的用户身份运行。),推荐你把你的模板放在工程内会带来很大便利。

打开你的设置文件(mywebsite/settings.py),在TEMPLATES设置中添加 DIRS 选项:

# mywebsite/settings.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(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/polls

属于工程的模板文件放在工程的模板目录(templates)。

现在,在 templates 目录内创建名为 admin 的目录

随后,将存放 Django 默认模板的目录(django/contrib/admin/templates)内的模板文件 admin/base_site.html 复制到工程的模板目录(templates/admin)内。

如果你想知道 Django 源码在你系统的哪个位置,运行以下命令:

 python -c "import django; print(django.__path__)"

 

接着,用你站点的名字(比如:投票管理后台)替换文件内的a标签中的文本 ``{{ site_header|default:_('Django administration') }}``(包含大括号)。完成后,你应该看到如下代码:

{% 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 }} 的文本。 {% 和 {{ 标签是 Django 模板语言的一部分。当 Django 渲染 admin/base_site.html 时,这个模板语言会被求值,生成最终的网页。

注意,所有的 Django 默认后台模板均可被复写。若要复写模板,像你修改 base_site.html 一样修改其它文件——先将其从默认目录中拷贝到你的自定义目录,再做修改。

2. 自定义你应用的模板

机智的你可能会问:DIRS  默认是空的,Django 是怎么找到默认的后台模板的?

因为 APP_DIRS 被置为 True,Django 会自动在每个应用包内递归查找 templates/ 子目录(不要忘了 django.contrib.admin 也是一个应用)。

我们的投票应用不是非常复杂,所以无需自定义应用的后台模板。不过,如果它变的更加复杂,需要修改 Django 的标准后台模板功能时,修改应用的模板会比工程的更加好。

这样,在其它工程包含这个投票应用时,可以确保它总是能找到需要的自定义模板文件(这样使得你的Django应用更具复用性)。

 

自定义后台主页

在类似的说明中,你可能想要自定义 Django 后台索引页的外观。

默认情况下,它展示了所有配置在INSTALLED_APPS中,已通过后台应用注册,按拼音排序的应用。你可能想对这个页面的布局做重大的修改。毕竟,索引页是后台的重要页面,它应该便于使用。

需要自定义的模板是 admin/index.html。(像上一节修改 admin/base_site.html 那样修改此文件——从默认目录中拷贝此文件至自定义模板目录)。打开此文件,你将看到它使用了一个叫做 app_list 的模板变量。这个变量包含了每个安装的 Django 应用。你可以用任何你期望的硬编码链接(链接至特定对象的管理页)替代使用这个变量。

 

接下来要做什么?

PS:

Django入门到实战的主要博客到这里就基本结束了,如果你对深入Django感兴趣,推荐你去查阅Django官方文档中文版——主题指南:https://docs.djangoproject.com/zh-hans/2.2/topics/ 深入介绍了Django的各个部分。有更多完整的关于 Django的 模板系统、模板引擎、表单框架和其它东西的信息。

如果你很熟悉 Python 打包,且还对学习如何把投票应用改成“可复用应用”感兴趣,那我们下一篇进阶博客可以再见咯。。。。

 

 

写在最后,欢迎关注一个一起学python的微信公众号:大众学python

掏出手机扫一扫:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛定谔的猫96

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值