第二十课 Admin后台管理

1. admin创建用户

创建管理员账号:


python manage.py createsuperuser# 按提示输入用户名、邮箱、密码

2. 注册模型

如果只是在admin中简单的展示及管理模型,需要在admin.py模块中使用admin.site.register将模型注册:


from django.contrib import adminfrom myproject.myapp.models import Authoradmin.site.register(Author)

但是,有时候我们需要对admin进行各种深度定制,以满足我们的需求。这就要使用Django为我们提供的ModelAdmin类了,例子:


from django.contrib import adminfrom myproject.myapp.models import Author# 创建一个ModelAdmin的子类class AuthorAdmin(admin.ModelAdmin):pass# 注册的时候,将原模型和ModelAdmin耦合起来admin.site.register(Author, AuthorAdmin)

3. 用装饰器注册注册模型

除了常用的admin.site.register(Author,AuthorAdmin)方式进行注册,还可以用装饰器的方式连接模型和ModelAdmin。例如:


from django.contrib import adminfrom .models import Author@admin.register(Author)class AuthorAdmin(admin.ModelAdmin):pass

这个装饰器可以接收一些模型类作为参数,以及一个可选的关键字参数site,例如:


from django.contrib import adminfrom .models import Author, Reader, Editorfrom myproject.admin_site import custom_admin_site@admin.register(Author, Reader, Editor, site=custom_admin_site)class PersonAdmin(admin.ModelAdmin):pass

4. ModelAdmin的属性

ModelAdmin非常灵活,它有许多内置属性,帮助我们自定义admin的界面和功能

(1)ModelAdmin.actions

一个列表,包含自定义的actions

(2)ModelAdmin.actions_on_top

是否在列表上方显示actions的下拉框,默认为True

(3)ModelAdmin.actions_on_bottom

是否在列表下方显示actions的下拉框,默认为False。效果见下面的图片

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4e8xBdnl-1608304247316)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091152267-1732573258.png)]

(4)ModelAdmin.actions_selection_counter

是否在actions下拉框右侧显示选中的对象的数量,默认为True,可改为False

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QcM1eQ98-1608304247318)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091201243-284760212.png)]

(5)ModelAdmin.date_hierarchy

根据你指定的日期相关的字段,为页面创建一个时间导航栏,可通过日期过滤对象。例如:


date_hierarchy = 'pub_date'

它的效果如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JdmjRu7N-1608304247319)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091206305-1467394714.png)]

也可以指定为关联的日期字段:


date_hierarchy = 'author__pub_date'

(6)ModelAdmin.empty_value_display

指定空白显示的内容。如果有些字段没有值,默认情况下会显示破折号“-”。这个选项可以让你自定义显示什么,例如:


from django.contrib import adminclass AuthorAdmin(admin.ModelAdmin):empty_value_display = '-empty-'

还可以为整个admin站点设置默认空白显示值,通过设置AdminSite.empty_value_display="xxxxxxx"。甚至为某个函数设置空白值,如下:


from django.contrib import adminclass AuthorAdmin(admin.ModelAdmin):fields = ('name', 'title', 'view_birth_date')def view_birth_date(self, obj):return obj.birth_date# 注意下面这句view_birth_date.empty_value_display = '???'

(7)ModelAdmin.exclude

不显示指定的某些字段

如下例有这么个模型:


from django.db import modelsclass Author(models.Model):name = models.CharField(max_length=100)title = models.CharField(max_length=3)birth_date = models.DateField(blank=True, null=True)

如果你不希望在页面内显示birth_date字段,那么这么设置:


from django.contrib import adminclass AuthorAdmin(admin.ModelAdmin):fields = ('name', 'title')

和这么设置是一样的:


from django.contrib import adminclass AuthorAdmin(admin.ModelAdmin):exclude = ('birth_date',)

(8)ModelAdmin.fields

按顺序显示指定的字段

可以通过组合元组的方式,让某些字段在同一行内显示。例如下面的做法“url”和“title”将在一行内,而“content”则在下一行:


class FlatPageAdmin(admin.ModelAdmin):fields = (('url', 'title'), 'content')

如果没有对field或fieldsets选项进行定义,那么Django将按照模型定义中的顺序,每一行显示一个字段的方式,逐个显示所有的非AutoField和editable=True的字段

(9)ModelAdmin.fieldsets

根据字段对页面进行分组显示或布局,fieldsets是一个二元元组的列表。每个二元元组代表一个<fieldset>

二元元组的格式为(name,field_options),name是一个表示该filedset标题的字符串,field_options是一个包含在该filedset内的字段列表。例如:


from django.contrib import adminclass FlatPageAdmin(admin.ModelAdmin):fieldsets = ((None, {'fields': ('url', 'title', 'content', 'sites')}),('Advanced options', {'classes': ('collapse',),'fields': ('registration_required', 'template_name'),}),)

它的页面看起来像下面的样子:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j8BhVJPf-1608304247321)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091218653-1760961744.png)]

filed_options字典内,可以使用下面这些关键字:

fields:一个必填的元组,包含要在fieldset中显示的字段。例如:


{'fields': ('first_name', 'last_name', 'address', 'city', 'state'),}

同样,它也可以像前面那样通过组合元组,实现多个字段在一行内的效果:


{'fields': (('first_name', 'last_name'), 'address', 'city', 'state'),}

fileds可以包含readonly_fields的值,作为只读字段。

classes:一个包含额外的CSS类的元组,例如:


{'classes': ('wide', 'extrapretty'),}

两个比较有用的样式是collaspewide,前者将fieldsets折叠起来,后者让它具备更宽的水平空间。

description:一个可选的额外的说明文本,放置在每个fieldset的顶部。但是,这里并没有对description的HTML语法进行转义,因此可能有时候会造成一些莫名其妙的显示,要忽略HTML的影响,请使用django.utils.html.escape()手动转义。

(10)ModelAdmin.filter_horizontal

水平扩展多对多字段。默认情况下,ManyTOManyField在admin的页面中会显示为一个select框。在需要选择大量对象时,这会有点困难。将ManyTOManyField添加到这个属性列表里后,页面就会对字段进行扩展,并提供过滤功能。如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fwOPoIfe-1608304247322)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091245944-1034707632.png)]

(11)ModelAdmin.filter_vertical

与上面的类似,不过是改成垂直布置了

(12)ModelAdmin.form

默认情况下,admin系统会为你的模型动态的创建ModelForm,它用于创建你的添加/修改页面的表单。我们可以编写自定义的ModelForm,在添加/修改页面覆盖默认的表单行为。

注意:如果你的ModelForm和ModelAdmin同时定义了exclude选项,那么ModelAdmin中的具有优先权,例如,下面的"age"字段将被排除,但是“name”字段将被显示:


from django import formsfrom django.contrib import adminfrom myapp.models import Personclass PersonForm(forms.ModelForm):class Meta:model = Personexclude = ['name']class PersonAdmin(admin.ModelAdmin):exclude = ['age']form = PersonForm

(13)ModelAdmin.formfield_overrides

代替传统的<textarea>,用于输入大段文字,例如:


from django.db import modelsfrom django.contrib import admin# 从对应的目录导入我们先前写好的widget和modelfrom myapp.widgets import RichTextEditorWidgetfrom myapp.models import MyModelclass MyModelAdmin(admin.ModelAdmin):formfield_overrides = {models.TextField: {'widget': RichTextEditorWidget},}

注意:在上面的外层字典中的键是一个实际的字段类,而不是字符串,对应的值又是一个字典;这些参数将被传递给form字段的__init__()方法

(14)ModelAdmin.inlines

参考InlineModelAdmin对象,就像ModelAdmin.get_formsets_with_inlines()一样

(15)ModelAdmin.list_display

指定显示在修改页面上的字段。这是一个很常用也是最重要的技巧之一。例如:


list_display = ('first_name', 'last_name')

如果你不设置这个属性,admin站点将只显示一列,内容是每个对象的__str__()方法返回的内容。

在list_display中,你可以设置四种值:

  • **模型的字段名 **

class PersonAdmin(admin.ModelAdmin):list_display = ('first_name', 'last_name')
  • **一个函数,它接收一个模型实例作为参数 **

def upper_case_name(obj):return ("%s %s" % (obj.first_name, obj.last_name)).upper()upper_case_name.short_description = 'Name'class PersonAdmin(admin.ModelAdmin):list_display = (upper_case_name,)
  • 一个表示ModelAdmin的某个属性的字符串

类似上面的函数调用,通过反射获取函数名,换了种写法而已,例如:


class PersonAdmin(admin.ModelAdmin):list_display = ('upper_case_name',)def upper_case_name(self, obj):return ("%s %s" % (obj.first_name, obj.last_name)).upper()upper_case_name.short_description = 'Name'
  • 一个表示模型的某个属性的字符串

类似第二种,但是此处的self是模型实例,引用的是模型的属性。参考下面的例子:


from django.db import modelsfrom django.contrib import adminclass Person(models.Model):name = models.CharField(max_length=50)birthday = models.DateField()def decade_born_in(self):return self.birthday.strftime('%Y')[:3] + "0's"decade_born_in.short_description = 'Birth decade'class PersonAdmin(admin.ModelAdmin):list_display = ('name', 'decade_born_in')

下面是一个完整的例子:


from django.db import modelsfrom django.contrib import adminfrom django.utils.html import format_htmlclass Person(models.Model):first_name = models.CharField(max_length=50)last_name = models.CharField(max_length=50)color_code = models.CharField(max_length=6)def colored_name(self):return '<span style="color: #%s;">%s %s</span>'%(self.color_code,self.first_name,self.last_name,)class PersonAdmin(admin.ModelAdmin):list_display = ('first_name', 'last_name', 'colored_name')

实际的效果如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MHad8vll-1608304247323)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091259160-1450506483.png)]

很明显,你是想要有个CSS效果,但Django把它当普通的字符串了。怎么办呢?用format_html()或者format_html_join()或者mark_safe()方法!


from django.db import modelsfrom django.contrib import admin# 需要先导入!from django.utils.html import format_htmlclass Person(models.Model):first_name = models.CharField(max_length=50)last_name = models.CharField(max_length=50)color_code = models.CharField(max_length=6)def colored_name(self):# 这里还是重点,注意调用方式,‘%’变成‘{}’了!return format_html('<span style="color: #{};">{} {}</span>',self.color_code,self.first_name,self.last_name,)class PersonAdmin(admin.ModelAdmin):list_display = ('first_name', 'last_name', 'colored_name')

下面看起来就会是你想要的结果了:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mGc0HfH6-1608304247324)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091304739-1198236764.png)]

  • 如果某个字段的值为None或空字符串或空的可迭代对象,那么默认显示为短横杠“-”,你可以使用AdminSite.empty_value_display在全局改写这一行为:

from django.contrib import adminadmin.site.empty_value_display = '(None)'

或者使用ModelAdmin.empty_value_display只改变某个类的行为:


class PersonAdmin(admin.ModelAdmin):empty_value_display = 'unknown'

或者更细粒度的只改变某个字段的这一行为:


class PersonAdmin(admin.ModelAdmin):list_display = ('name', 'birth_date_view')def birth_date_view(self, obj):return obj.birth_datebirth_date_view.empty_value_display = 'unknown'
  • 默认情况下,一个返回布尔值的方法在list_display中显示为True或者False的:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bSXv76j4-1608304247325)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091313357-1469253605.png)]

但如果你给这个方法添加一个boolean的属性并赋值为True,它将显示为on/off的图标,如下图:


from django.db import modelsfrom django.contrib import adminclass Person(models.Model):first_name = models.CharField(max_length=50)birthday = models.DateField()def born_in_fifties(self):return self.birthday.strftime('%Y')[:3] == '195'# 关键在这里born_in_fifties.boolean = Trueclass PersonAdmin(admin.ModelAdmin):# 官方文档这里有错,将'name'改为'first_name' list_display = ('first_name', 'born_in_fifties')

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Na5Mub3P-1608304247326)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091320738-731208550.png)]

  • 通常情况下,在list_display列表里的元素如果不是数据库内的某个具体字段,是不能根据它进行排序的。但是如果给这个字段添加一个admin_order_field属性,并赋值一个具体的数据库内的字段,则可以按这个字段对原字段进行排序,如下所示:

from django.db import modelsfrom django.contrib import adminfrom django.utils.html import format_htmlclass Person(models.Model):first_name = models.CharField(max_length=50)color_code = models.CharField(max_length=6)def colored_first_name(self):return format_html('<span style="color: #{};">{}</span>',self.color_code,self.first_name,)# 就是这一句了!colored_first_name.admin_order_field = 'first_name'class PersonAdmin(admin.ModelAdmin):list_display = ('first_name', 'colored_first_name')

本来colored_first_name是不能排序的,给它的admin_order_field赋值first_name后,就依托first_name进行排序了。

要降序的话,使用连字符“-”前缀:


colored_first_name.admin_order_field = '-first_name'

还可以跨表跨关系引用:


class Blog(models.Model):title = models.CharField(max_length=255)author = models.ForeignKey(Person, on_delete=models.CASCADE)class BlogAdmin(admin.ModelAdmin):list_display = ('title', 'author', 'author_first_name')def author_first_name(self, obj):return obj.author.first_name# 指定了另一张表的first_name作为排序的依据author_first_name.admin_order_field = 'author__first_name'
  • list_display里的元素还可以是某个属性。但是请注意的是,如果使用python的@property方式来构造一个属性,则不能给它添加short_description描述,只有使用property()函数的方法构造属性的时候,才可以添加short_description描述,如下:

class Person(models.Model):first_name = models.CharField(max_length=50)last_name = models.CharField(max_length=50)def my_property(self):return self.first_name + ' ' + self.last_namemy_property.short_description = "Full name of the person"full_name = property(my_property)class PersonAdmin(admin.ModelAdmin):list_display = ('full_name',)
  • list_display中的每个字段名在HTML中都将自动生成CSS类属性,在th标签中以column-<field_name>的格式,你可以通过它,对前端进行自定义或调整,例如设置宽度等等

(16)ModelAdmin.list_display_links

指定用于链接修改页面的字段。通常情况,list_display列表中的第一个元素被作为指向目标修改页面的超级链接点。但是,使用list_display_links可以帮你修改这一默认配置

  • 如果设置为None,则根本没有链接了,你无法跳到目标的修改页面

  • 或者设置为一个字段的元组或列表,每一个元素都是一个指向修改页面的链接。但是要使用list_display_links,必须先有list_display

下面这个例子中first_namelast_name都可以点击并跳转到修改页面。


class PersonAdmin(admin.ModelAdmin):list_display = ('first_name', 'last_name', 'birthday')list_display_links = ('first_name', 'last_name')

而如果这样,你将没有任何链接:


class AuditEntryAdmin(admin.ModelAdmin):list_display = ('timestamp', 'message')list_display_links = None

(17)ModelAdmin.list_editable

指定在修改列表页面中哪些字段可以被编辑。指定的字段将显示为编辑框,可修改后直接批量保存,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VNz1VBTT-1608304247326)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091333391-1113975110.png)]

(18)ModelAdmin.list_filter

设置list_filter属性后,可以激活修改列表页面的右侧边栏,用于对列表元素进行过滤,如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eMjctotU-1608304247327)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091340829-862747392.png)]

list_filter必须是一个元组或列表,其元素是如下类型之一:

  • 某个字段名,但该字段必须是BooleanField、CharField、DateField、DateTimeField、IntegerField、ForeignKey或者ManyToManyField中的一种。例如:

class PersonAdmin(admin.ModelAdmin):list_filter = ('is_staff', 'company')

在这里,你可以利用双下划线进行跨表关联,如下例:


class PersonAdmin(admin.UserAdmin):list_filter = ('company__name',)
  • 一个继承django.contrib.admin.SimpleListFilter的类。你要给这个类提供title和parameter_name的值,并重写lookups和queryset方法。例如:

from datetime import datefrom django.contrib import adminfrom django.utils.translation import ugettext_lazy as _class DecadeBornListFilter(admin.SimpleListFilter):# 提供一个可读的标题title = _('出生年代')# 用于URL查询的参数.parameter_name = 'decade'def lookups(self, request, model_admin):"""返回一个二维元组。每个元组的第一个元素是用于URL查询的真实值,这个值会被self.value()方法获取,并作为queryset方法的选择条件。第二个元素则是可读的显示在admin页面右边侧栏的过滤选项。        """return (('80s', _('80年代')),('90s', _('90年代')),)def queryset(self, request, queryset):"""根据self.value()方法获取的条件值的不同执行具体的查询操作。并返回相应的结果。"""if self.value() == '80s':return queryset.filter(birthday__gte=date(1980, 1, 1),birthday__lte=date(1989, 12, 31))if self.value() == '90s':return queryset.filter(birthday__gte=date(1990, 1, 1),birthday__lte=date(1999, 12, 31))class PersonAdmin(admin.ModelAdmin):list_display = ('first_name', 'last_name', "colored_first_name",'birthday')list_filter = (DecadeBornListFilter,)

其效果如下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l3dzJtr2-1608304247328)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091349396-177806276.png)]

注意:为了方便,我们通常会将HttpRequest对象传递给lookups和queryset方法,如下所示:


class AuthDecadeBornListFilter(DecadeBornListFilter):def lookups(self, request, model_admin):if request.user.is_superuser:return super(AuthDecadeBornListFilter, self).lookups(request, model_admin)def queryset(self, request, queryset):if request.user.is_superuser:return super(AuthDecadeBornListFilter, self).queryset(request, queryset)

同样的,我们默认将ModelAdmin对象传递给lookups方法。下面的例子根据查询结果,调整过滤选项,如果某个年代没有符合的对象,则这个选项不会在右边的过滤栏中显示:


class AdvancedDecadeBornListFilter(DecadeBornListFilter):def lookups(self, request, model_admin):"""只有存在确切的对象,并且它出生在对应年代时,才会出现这个过滤选项。"""qs = model_admin.get_queryset(request)if qs.filter(birthday__gte=date(1980, 1, 1),birthday__lte=date(1989, 12, 31)).exists():yield ('80s', _('in the eighties'))if qs.filter(birthday__gte=date(1990, 1, 1),birthday__lte=date(1999, 12, 31)).exists():yield ('90s', _('in the nineties'))
  • 也可以是一个元组。它的第一个元素是个字段名,第二个元素则是继承了django.contrib.admin.FieldListFilter的类。例如:

class PersonAdmin(admin.ModelAdmin):list_filter = (('is_staff', admin.BooleanFieldListFilter),)

你可以使用RelatedOnlyFieldListFilter限制关联的对象。假设author是关联User模型的ForeignKey,下面的用法将只选择那些出过书的user而不是所有的user:


class BookAdmin(admin.ModelAdmin):list_filter = (('author', admin.RelatedOnlyFieldListFilter),)

另外,其template属性可以指定渲染的模板,如下则指定了一个自定义的模板。(Django默认的模板为admin/filter.html)


class FilterWithCustomTemplate(admin.SimpleListFilter):template = "custom_template.html"

(19)ModelAdmin.list_max_show_all

设置一个数值,当列表元素总数小于这个值的时候,将显示一个“show all”链接,点击后就能看到一个展示了所有元素的页面。该值默认为200

(20)ModelAdmin.list_per_page

设置每页显示多少个元素。Django自动帮你分页。默认为100

(21)ModelAdmin.list_select_related

如果设置了list_select_related属性,Django将会使用select_related()方法查询数据,这可能会帮助你减少一些数据库访问

属性的值可以是布尔值、元组或列表,默认为False。当值为True时,将始终调用select_related()方法;如果值为False,Django将查看list_display属性,只对ForeignKey字段调用select_related()方法。例如:


class ArticleAdmin(admin.ModelAdmin):list_select_related = ('author', 'category')

(22)ModelAdmin.ordering

设置排序的方式

属性的值必须为一个元组或列表,格式和模型的ordering参数一样。如果不设置这个属性,Django将按默认方式进行排序。如果你想进行动态排序,请自己实现get_ordering()方法

(23)ModelAdmin.paginator

指定用于分页的分页器。默认情况下,分页器用的是Django自带的django.core.paginator.Paginator。如果自定义分页器的构造函数接口和django.core.paginator.Paginator的不一样,那你还需要自己实现ModelAdmin.get_paginator()方法

(24)ModelAdmin.prepopulated_fields

设置预填充字段。不接收DateTimeField、ForeignKey和ManyToManyField类型的字段。


class ArticleAdmin(admin.ModelAdmin):prepopulated_fields = {"slug": ("title",)}

(25)ModelAdmin.preserve_filters

默认情况下,当你对目标进行创建、编辑或删除操作后,页面会依然保持原来的过滤状态。将preserve_filters设为False后,则会返回未过滤状态。

(26)ModelAdmin.radio_fields

默认情况下,Django使用select标签显示ForeignKey或choices集合。如果将这种字段设置为radio_fields,则会以radio_box标签的形式展示。下面的例子假设group是Person模型的ForeignKey字段


class PersonAdmin(admin.ModelAdmin):# 垂直布局。(肯定也有水平布局HORIZONTAL的啦)radio_fields = {"group": admin.VERTICAL}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CSRFs7V8-1608304247328)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091403227-174783789.png)]

(27)ModelAdmin.raw_id_fields

这个属性会改变默认的ForeignKey和ManyToManyField的展示方式,它会变成一个输入框,用于输入关联对象的主键id。对于ManyToManyField,id以逗号分隔。并且再输入框右侧提供一个放大镜的图标,你可以点击进入选择界面。例如:


class PersonAdmin(admin.ModelAdmin):raw_id_fields = ("group",)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nULmp4Zb-1608304247329)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091407928-780759103.png)]

(28)ModelAdmin.readonly_fields

该属性包含的字段在页面内将展示为不可编辑状态。它还可以展示模型或者ModelAdmin本身的方法的返回值,类似ModelAdmin.list_display的行为。例如:


from django.contrib import adminfrom django.utils.html import format_html_joinfrom django.utils.safestring import mark_safeclass PersonAdmin(admin.ModelAdmin):readonly_fields = ('address_report',)def address_report(self, instance):# assuming get_full_address() returns a list of strings# for each line of the address and you want to separate each# line by a linebreakreturn format_html_join(mark_safe('<br/>'),'{}',((line,) for line in instance.get_full_address()),) or mark_safe("<span class='errors'>I can't determine this address.</span>")# short_description functions like a model field's verbose_nameaddress_report.short_description = "Address"

(29)ModelAdmin.save_as

默认情况下,它的值为False。如果设置为True,那么右下角的“Save and add another”按钮将被替换成“Save as new”,意思也变成保存为一个新的对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bk2ECbXS-1608304247329)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091414760-902022906.png)]

(30)ModelAdmin.save_as_continue

默认值为True, 在保存新对象后跳转到该对象的修改页面。但是如果这时save_as_continue=False,则会跳转到元素列表页面。

(31)ModelAdmin.save_on_top

默认为False。 设为True时,页面的顶部会提供同样的一系列保存按钮。

(32)ModelAdmin.search_fields

设置这个属性,可以为admin的修改列表页面添加一个搜索框。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lkzE5Ne2-1608304247329)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091420591-1475213139.png)]

被搜索的字段可以是CharField或者TextField文本类型,也可以通过双下划线进行ForeignKey或者ManyToManyField的查询,格式为search_fields = ['foreign_key__related_fieldname'].

例如:如果作者是博客的ForeignKey字段,下面的方式将通过作者的email地址来查询对应的博客,也就是email地址是查询值的作者所写的所有博客。


search_fields = ['user__email']

当你在搜索框里输入一些文本的时候,Django会将文本分割成一个一个的关键字,并返回所有包含这些关键字的对象,必须注意的是,每个关键词至少得是search_fields其中之一。例如,如果search_fields['first_name', 'last_name'],当用户输入John lennon时(注意中间的空格),Django将执行等同于下面的SQL语法WHERE子句:


WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%') AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%')

如果要执行更加严格的匹配或搜索,可以使用一些元字符,例如“^”。类似正则,它代表从开头匹配。例如,如果search_fields['^first_name','^last_name'],当用户输入“John lennon”时(注意中间的空格),Django将执行等同于下面的SQL语法WHERE子句:


WHERE (first_name ILIKE 'john%' OR last_name ILIKE 'john%') AND (first_name ILIKE 'lennon%' OR last_name ILIKE 'lennon%')

也可以使用“=”,来进行区分大小写的并绝对相等的严格匹配。例如,如果search_fields['=first_name','=last_name'],当用户输入“John lennon”时(注意中间的空格),Django将执行等同于下面的SQL语法WHERE子句:


WHERE (first_name ILIKE 'john' OR last_name ILIKE 'john') AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon')

(33)ModelAdmin.show_full_result_count

用于设置是否显示一个过滤后的对象总数的提示信息,例如“99 results (103 total)”。如果它被设置为False,那么显示的将是“ 99 results (Show all)”。 默认情况下,它的值为True,这将会对整个表进行一个count操作,在表很大的时候,可能会耗费一定的时间和资源。

(34)ModelAdmin.view_on_site

这个属性可以控制是否在admin页面显示“View site”的链接。这个链接主要用于跳转到你指定的URL页面。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ucxLIPZ7-1608304247330)(/home/pyvip/py_case/python 笔记/图片/1762677-20201006091428506-1595310635.png)]

属性的值可以是布尔值或某个调用。如果是True(默认值),对象的get_absolute_url()方法将被调用并生成url

如果你的模型有一个get_absolute_url()方法,但你不想显示“View site”链接,你只需要将view_on_site属性设置为False。


from django.contrib import adminclass PersonAdmin(admin.ModelAdmin):view_on_site = False

如果属性的值是一个调用,它将接收一个模型实例作为参数:


from django.contrib import adminfrom django.urls import reverseclass PersonAdmin(admin.ModelAdmin):def view_on_site(self, obj):url = reverse('person-detail', kwargs={'slug': obj.slug})return 'https://example.com' + url

(35)ModelAdmin.sortable_by

默认情况下,“更改列表”页面允许按 list_display中指定的所有模型字段进行排序。

如果要对某些列禁用排序功能,可以将sortable_by设置为要排序的list_display子集的集合(例如list、tuple或set)。空集合将禁用所有列的排序。

如果需要动态指定此列表,请改为实现get_sortable_by()方法

5. 常用的ModelAdmin属性

列表页属性

  • list_display:显示字段,可以点击列头进行排序

  • list_filter:过滤字段,过滤框会出现在右侧

  • search_fields:搜索字段,搜索框会出现在上侧

  • list_per_page:分页,分页框会出现在下侧

添加、修改页属性,两个属性,二者选一

  • fields:属性的先后顺序

  • fieldsets:属性分组


from django.contrib import adminfrom .models import *# Register your models here.class BlogAdimin(admin.ModelAdmin):# 列表页list_display = ['title', 'author', 'content', 'cre_time'] # 在页面展示模型字段list_display_links = ['title', 'author'] # 点击可以跳转的字段search_fields = ['title', 'author', 'cre_time'] # 设置搜索框,定义可以搜索的字段list_filter = ['title', 'author', 'content', 'cre_time'] # 过滤器list_per_page = 10 # 设置分页# 详情页fields = ['title', 'author', 'content']admin.site.register(Blog, BlogAdimin)

第二十课 Django Admin后台管理相关推荐

  1. Django admin后台管理页面的常用设置

    Django admin后台管理页面的常用设置 选择列表选项choices # filename: models.pyfrom django.db import models# 例1 int类型:ST ...

  2. django admin后台管理插件django-suit入门

    前言 用过django的同学大概都知道,admin后台那个丑到爆的界面: 虽然程序猿不太那么讲究审美,但是这么吃藕的一个界面,反正搁我我是忍不了.不过呢,还好django扩展能力还是挺强的,有牛人开发 ...

  3. Django Admin后台管理功能使用

    前言 用过Django框架的童鞋肯定都知道,在创建完Django项目后,每个app下,都会有一个urls.py文件,里边会有如下几行: 1 2 3 4 5 from django.contrib im ...

  4. python的django后台管理_python测试开发django-17.admin后台管理

    前言 通常一个网站开发,需要有个后台管理功能,比如用后台管理发布文章,添加用户之类的操作.django的admin后台管理主要可以实现以下功能 基于admin模块,可以实现类似数据库客户端的功能,对数 ...

  5. django21:admin后台管理\media配置\图片防盗链\暴露后端资源\路由分发\时间分类

    admin后台管理 创建超级用户 createsuperuser 1.到应用下的admin.py注册模型表 from django.contrib import admin from blog imp ...

  6. DJANGO ADMIN后台设置

    Django自带的后台管理是Django明显特色之一,可以让我们快速便捷管理数据.后台管理可以在各个app的admin.py文件中进行控制.以下是我最近摸索总结出比较实用的配置.若你有什么比较好的配置 ...

  7. admin后台管理及数据库表管理

    admin 后台数据库管理 django 提供了比较完善的后台管理数据库的接口,可供开发过程中调用和测试使用 django 会搜集所有已注册的模型类,为这些模型类提拱数据管理界面,供开发者使用 使用步 ...

  8. 苹果cmsv10首涂第二十二套带后台系统原创多功能自适应高端模板

    苹果cmsv10首涂第二十二套带后台系统原创多功能自适应高端模板 苹果cmsv10高权重简洁模板带广告位自适应模板 此款模板带资讯,会员中心.明星.剧情.还有十几个固定广告位.小白做站的必选苹果cms ...

  9. Django admin 后台定制库存管理的中的入库管理

    Django 的admin或xadmin定制后台管理十分方便,在此就不多说了,我今天想说的一个问题是,如何实现admin的不同表间不同字段的管理操作(描述不太清晰,不要在意).(使用MySQL数据库) ...

最新文章

  1. P5568 [SDOI2008]校门外的区间(离散数学应用+线段树+开闭区间处理)(校门三部曲)难度⭐⭐⭐⭐
  2. 从介质部署额外域控制器
  3. 通过Cookie实现客户端与服务端会话的维持;
  4. Go语言范围(Range)
  5. 从Windows计算机上完全删除iTunes和其他Apple软件
  6. [js] innerHTML与outerHTML有什么区别?
  7. 这些大佬告诉你,在先进计算与AI领域该往哪个方向冲!
  8. VMware esxi 4.0如何更换序列号
  9. UBUNTU使用GITHUB
  10. 密码学09(SM3算法)
  11. [数值计算-11]:多元函数求最小值 - 偏导数与梯度下降法Python法代码示例
  12. TinyG 入门06
  13. NET开发邮件发送功能的全面教程(含邮件组件源码)(
  14. 基于python3的tkinter和scapy可视化报文构造工具(六)
  15. 2023 年 5 大人工智能 (AI) 趋势
  16. MySQL中IN对NULL的处理
  17. FCES2019第二天 | BY AI,AI技术赋能教育的N种可能
  18. HR干货,怎样做好企业员工的晋升
  19. 如何实现bilibili最新头部景深效果~炫酷
  20. 【数据质量】数据质量管理工具预研——Griffin VS Deequ VS Great expectations VS Qualitis

热门文章

  1. JAVA 中的 - 是什么意思?
  2. 显示器要申请BS 476-7 怎么送样?跟显示屏一样吗
  3. MS08-067漏洞简谈与利用
  4. 修改C:\Users 下面文件夹的名称
  5. python动态爱心曲线_【Python】五分钟画一条动态心形曲线~
  6. UE4 编辑器内修改贴图分辨率
  7. UE4 虚幻引擎,更改源代码编辑器 Visual Studio ,Rider
  8. Helly定理与证明
  9. Zabbix通过JMX监控Java应用
  10. Redis分布式锁的原理、作用及实现(简单易懂)