django官方demo翻译简化版 七(demo终)
本篇集中于讲解修改django自带的admin后台的外观及样式。
定制form表单
通过把Question 模型注册在admin.site.register(Question)里面。django可以生成一个默认的表单结构。但是我们经常会需要一些自定义的表单结构。你可以在注册的时候提供你的需求信息来达到定制的效果。
现在来实现这个,修改admin.py文件:
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类,然后把它作为一个参数传递给admin.site.register())。
上述修改会让Publication date显示在Question前面:

这种操作在只有2个字段值的时候可能看起来没有什么,但是在字段值很多的情况下,这种排序会很有效果。
然后在字段很多的时候,你可能会想要把这些表单改成自定义字段的形式:
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里的元组里的第一个元素就是自定义字段的标题。现在我们的表单的展示如下图:

增加相关的类
到了这一步,我们的Question 类的页面已经写好了,但是还有个问题需要处理,那就是每个问题都有多个选项,但是我们并没有展示出来。
这个问题有2个解决方法。第一个方法是在admin里面注册Choice,就像前面注册Question一样:
polls/admin.py from django.contrib import admin from .models import Choice, Question # ... admin.site.register(Choice)
现在“Choices”是一个在django admin里面的可选项。“Add choice”表单将会像下图显示一样:

在这个表单中,“Question”是一个可选下拉框。django知道ForeignKey应该在admin里以一个可选下拉框的形式出现。在我们的这种情况下,只会展示一个问题。
同时,我们需要注意下“Question.”旁边的 “Add Another”链接。每个拥有外键的对象都会有这个功能。当你点击这个链接的时候,都会有一个新增问题弹框出来让你做新增操作。一旦你填写并提交保存后,就会把这个记录提交到数据库并且动态的将你选的choice关联到这个问题上面。
但是,说实话,这种方式并不高效。假如你可以在增加问题的时候就可以添加选项的话,效率应该更高。
移掉前面我们使用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,我们将在Question的管理页面上编辑Choice类,并且会默认提供三个选项。
重新加载这个程序,然后你会看到如下界面:

它会通过extra字段值来确定每个问题会默认提供多少个选项。
在choice下面还有“Add another Choice”链接可以使用。你点击后就会新增一个choice选项,然后你可以通过选项上的“X”来进行删除。但是需要注意的是,默认提供的三个选项是无法被删除的。如下图:

这里还有一个小问题。现在的这种方式,choice占用了太多的屏幕空间。基于这种情况,django提供了另外一种方式:
polls/admin.py class ChoiceInline(admin.TabularInline): #...
通过使用TabularInline而不是StackedInline,相关联的部分会使用更少的空间:

注意到旁边的“Delete?” 字段没有?这个字段允许你删除通过“Add Another Choice”方式新增的选项,默认的三个无法删除。
自定义admin改变列表
经过我们一系列的修改后,现在的Question管理页面看起来好了很多,现在我们对“change list” 页面做一些调整--也就是展示所有问题的页面。
下面这个是现在的样子:

一般情况下,django会默认每个对象都是str()类型的。但是有些情况下,我们需要做一些特别的字段展示。为了实现这个目的,我们使用list_display这个admin选项,它是一个字段名元组,作为列显示在字段的change list上:
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')
现在问题的修改页面会展示如下:

你可以通过点击字段的头部来根据它的值来排序除了was_published_recently以外,因为不支持按照方法的值来进行排序。注意was_published_recently 的列头是默认使用它的方法名称的,它每一列的值都会是这个问题调用这个方法后的返回结果。
你可以通过给这个方法增加一些属性值来改进,就像下面这样:
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?'
关于这些方法的额外属性部分可以查看,见官网的 list_display.
再次编辑文件polls/admin.py,然后给Question修改页面再次加些内容:加个过滤器list_filter.在QuestionAdmin里增加如下代码:
list_filter = ['pub_date']
这个操作会在问题修改页增加一个以pub_date 为依据的过滤器:

过滤器的展示结果依据于你选择的过滤器的筛选条件。由于pub_date是一个DateTimeField类型的,django会自动给它分配几个过滤器筛选条件:Any date”, “Today”, “Past 7 days”, “This month”, “This year”。
让我们增加一些搜索的能力:
search_fields = ['question_text']
这种方式会在问题修改页面顶部增加一个搜索框。当有人输入了搜索词时,django将会搜索question_text字段。你可以使用很多的这种字段-但是最好不要太多,多了会对数据库压力较大。
问题修改页面的分页默认最大是展示100个数据。Change list pagination, search boxes, filters, date-hierarchies, and column-header-ordering 这些你都可以在这里面使用。
自定义admin的外观
很明显,在每个管理页面顶部出现“Django administration”是很可笑的事情。
你可以通过使用django的模板系统来修改它。
自定义你的项目模板
在你的项目目录下也就是manage.py文件所在位置新建一个目录templates。然后在你的配置文件mysite/settings.py里的配置项TEMPLATES下新建一个DIRS选项:
mysite/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的搜索路径。
管理模板
就像静态文件一样,我们可以把模板全部放到一个大目录下,这样可以工作的很好。但是把模板放到各自的应用的目录下会比这样全部放到一个目录下更好。
现在在templates目录下创建一个admin目录。从django/contrib/admin/templates里把admin/base_site.html复制到这个新建的目录下。
#从哪里查看django的资源文件 #假如你不知道从哪获取django的资源文件在哪里的话,运行下面的命令: python -c "import django; print(django.__path__)"
然后编辑文件,用你自己的网站名称来替换掉{{ 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时,会自动去使用这些标签匹配到的内容去替换这些标签,然后生成html显示出来。
注意django里的任何默认admin 模板都可以被重写的。要重写的话,按照我们前面说的对base_site.html做的修改site_header的方式来做就可以了--从默认目录下复杂到你的自定义目录下,然后修改就好。
自定义你的应用模板
一些机智的读者可能会问,假如默认的DIRS 本身就是空的,那么django怎么去寻找默认的admin模板?答案就是 APP_DIRS设置为了True的话,django会自动在项目下的应用下的寻找templates/目录。记得django.contrib.admin也是一个应用。
我们的demo程序很简单,所以不需要自定义admin 模板。但是假如它变得很复杂并且需要修改它的标准管理模板的话,之间修改标准管理模板比在项目中修改更好。那么只要你确保它可以获取到自定义模板,那么你可以在项目中的任何地方包括poll应用。
自定义管理欢迎页面
我们也可能会有需要修改管理的欢迎页面。
默认情况下,它会展示注册在管理应用并且在INSTALLED_APPS下的应用,通过字母排序。你可能想要对这个页面做一些重要的改变。最后,管理欢迎页面可能是管理后台最重要的页面之一,它应该被设计成使用起来很方便的那种。
admin的欢迎页面使用的模板是admin/index.html。像前面那样复制然后放到你需要的位置。编辑这个文件,然后你可以在里面找到app_list这个变量。这个变量包括了所有django安装的app。你可以使用是我们经常会需要一些自定义的表单结构。你可以在注册的时候提供你的需求信息来达到定制的效果。
现在来实现这个,修改admin.py文件:
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类,然后把它作为一个参数传递给admin.site.register())。
上述修改会让Publication date显示在Question前面:

这种操作在只有2个字段值的时候可能看起来没有什么,但是在字段值很多的情况下,这种排序会很有效果。
然后在字段很多的时候,你可能会想要把这些表单改成自定义字段的形式:
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里的元组里的第一个元素就是自定义字段的标题。现在我们的表单的展示如下图:

增加相关的类
到了这一步,我们的Question 类的页面已经写好了,但是还有个问题需要处理,那就是每个问题都有多个选项,但是我们并没有展示出来。
这个问题有2个解决方法。第一个方法是在admin里面注册Choice,就像前面注册Question一样:
polls/admin.py
from django.contrib import admin
from .models import Choice, Question
# ...
admin.site.register(Choice)
现在“Choices”是一个在django admin里面的可选项。“Add choice”表单将会像下图显示一样:

在这个表单中,“Question”是一个可选下拉框。django知道ForeignKey应该在admin里以一个可选下拉框的形式出现。在我们的这种情况下,只会展示一个问题。
同时,我们需要注意下“Question.”旁边的 “Add Another”链接。每个拥有外键的对象都会有这个功能。当你点击这个链接的时候,都会有一个新增问题弹框出来让你做新增操作。一旦你填写并提交保存后,就会把这个记录提交到数据库并且动态的将你选的choice关联到这个问题上面。
但是,说实话,这种方式并不高效。假如你可以在增加问题的时候就可以添加选项的话,效率应该更高。
移掉前面我们使用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,我们将在Question的管理页面上编辑Choice类,并且会默认提供三个选项。
重新加载这个程序,然后你会看到如下界面:

它会通过extra字段值来确定每个问题会默认提供多少个选项。
在choice下面还有“Add another Choice”链接可以使用。你点击后就会新增一个choice选项,然后你可以通过选项上的“X”来进行删除。但是需要注意的是,默认提供的三个选项是无法被删除的。如下图:

这里还有一个小问题。现在的这种方式,choice占用了太多的屏幕空间。基于这种情况,django提供了另外一种方式:
polls/admin.py
class ChoiceInline(admin.TabularInline):
#...
通过使用TabularInline而不是StackedInline,相关联的部分会使用更少的空间:

注意到旁边的“Delete?” 字段没有?这个字段允许你删除通过“Add Another Choice”方式新增的选项,默认的三个无法删除。
自定义admin改变列表
经过我们一系列的修改后,现在的Question管理页面看起来好了很多,现在我们对“change list” 页面做一些调整--也就是展示所有问题的页面。
下面这个是现在的样子:

一般情况下,django会默认每个对象都是str()类型的。但是有些情况下,我们需要做一些特别的字段展示。为了实现这个目的,我们使用list_display这个admin选项,它是一个字段名元组,作为列显示在字段的change list上:
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')
现在问题的修改页面会展示如下:

你可以通过点击字段的头部来根据它的值来排序除了was_published_recently以外,因为不支持按照方法的值来进行排序。注意was_published_recently 的列头是默认使用它的方法名称的,它每一列的值都会是这个问题调用这个方法后的返回结果。
你可以通过给这个方法增加一些属性值来改进,就像下面这样:
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?'
关于这些方法的额外属性部分可以查看,见官网的 list_display.
再次编辑文件polls/admin.py,然后给Question修改页面再次加些内容:加个过滤器list_filter.在QuestionAdmin里增加如下代码:
list_filter = ['pub_date']
这个操作会在问题修改页增加一个以pub_date 为依据的过滤器:

过滤器的展示结果依据于你选择的过滤器的筛选条件。由于pub_date是一个DateTimeField类型的,django会自动给它分配几个过滤器筛选条件:Any date”, “Today”, “Past 7 days”, “This month”, “This year”。
让我们增加一些搜索的能力:
search_fields = ['question_text']
这种方式会在问题修改页面顶部增加一个搜索框。当有人输入了搜索词时,django将会搜索question_text字段。你可以使用很多的这种字段-但是最好不要太多,多了会对数据库压力较大。
问题修改页面的分页默认最大是展示100个数据。Change list pagination, search boxes, filters, date-hierarchies, and column-header-ordering 这些你都可以在这里面使用。
自定义admin的外观
很明显,在每个管理页面顶部出现“Django administration”是很可笑的事情。
你可以通过使用django的模板系统来修改它。
自定义你的项目模板
在你的项目目录下也就是manage.py文件所在位置新建一个目录templates。然后在你的配置文件mysite/settings.py里的配置项TEMPLATES下新建一个DIRS选项:
mysite/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的搜索路径。
管理模板
就像静态文件一样,我们可以把模板全部放到一个大目录下,这样可以工作的很好。但是把模板放到各自的应用的目录下会比这样全部放到一个目录下更好。
现在在templates目录下创建一个admin目录。从django/contrib/admin/templates里把admin/base_site.html复制到这个新建的目录下。
#从哪里查看django的资源文件
#假如你不知道从哪获取django的资源文件在哪里的话,运行下面的命令:
python -c "import django; print(django.__path__)"
然后编辑文件,用你自己的网站名称来替换掉{{ 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时,会自动去使用这些标签匹配到的内容去替换这些标签,然后生成html显示出来。
注意django里的任何默认admin 模板都可以被重写的。要重写的话,按照我们前面说的对base_site.html做的修改site_header的方式来做就可以了--从默认目录下复杂到你的自定义目录下,然后修改就好。
自定义你的应用模板
一些机智的读者可能会问,假如默认的DIRS 本身就是空的,那么django怎么去寻找默认的admin模板?答案就是 APP_DIRS设置为了True的话,django会自动在项目下的应用下的寻找templates/目录。记得django.contrib.admin也是一个应用。
我们的demo程序很简单,所以不需要自定义admin 模板。但是假如它变得很复杂并且需要修改它的标准管理模板的话,之间修改标准管理模板比在项目中修改更好。那么只要你确保它可以获取到自定义模板,那么你可以在项目中的任何地方包括poll应用。
自定义管理欢迎页面
我们也可能会有需要修改管理的欢迎页面。
默认情况下,它会展示注册在管理应用并且在INSTALLED_APPS下的应用,通过字母排序。你可能想要对这个页面做一些重要的改变。最后,管理欢迎页面可能是管理后台最重要的页面之一,它应该被设计成使用起来很方便的那种。
admin的欢迎页面使用的模板是admin/index.html。像前面那样复制然后放到你需要的位置。编辑这个文件,然后你可以在里面找到app_list这个变量。这个变量包括了所有django安装的app。你可以使用任何你觉得更好的方式来硬编码的链接到管理页面上来替代这种方式。
浙公网安备 33010602011771号