一、 配置admin
在admin.py中为model.py的每个字段注册至admin后台管理界面:
方法一:
class PostAdmin(admin.ModelAdmin):
pass
admin.site.register(Post, PostAdmin)
方法二:
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
pass
二、定制site和admin_list
- 定制site
typeidea/custom_site.py
from django.contrib.admin import AdminSite
class CustomSite(AdminSite):
site_header = 'Typeidea'
site_title = 'Typeidea后台管理'
index_title = '首页'
custom_site = CustomSite(name='cus_admin')
blog/admin.py
@admin.register(Post, site=custom_site)
class PostAdmin(admin.ModelAdmin):
pass
@admin.register(Category, site=custom_site)
class CategoryAdmin(admin.ModelAdmin):
pass
@admin.register(Tag, site=custom_site)
class TagAdmin(admin.ModelAdmin):
pass
blog/urls.py
url(r'^cus_admin/', custom_site.urls),
- 定制admin_list
# 显示页面
list_display = ['title', 'category', 'status', 'owner', 'created_time']
list_display_links = ['title']
list_filter = ['category', 'owner']
search_fields = ['title', 'category__name', 'owner__username']
show_full_result_count = True
actions_on_top = True
actions_on_bottom = True
date_hierarchy = 'created_time'
list_editable = ['status']
fieldsets = (
('基础配置', {
'fields': (('category', 'title'), 'content')
}),
('高级配置', {
'classes': ('collapse', 'addon'),
'fields': ('tags',)
})
)
三、自定义字段
def operator(self, obj):
return format_html(
'<a href="{}">编辑</a>',
# '/cus_admin/blog/post/%s/' % obj.id
reverse('cus_admin:blog_post_change', args=(obj.id,))
)
# operator.allow_tags = True
operator.short_description = '操作'
四、自定义Form
还是只针对postadmin来增加form, 在blog目录下增加文件(模块)adminforms.py 这里要命名为adminforms而不是forms,只为了跟前台针对用户输入进行处理的form区分开来。里面编写代码,定义form。关于form的作用,我们之前有讲到,form跟model其实是耦合在一起的,或者说form跟model的逻辑是一致的,model是对数据库中字段的抽象,form是对用户输入以及model中要展示数据的抽象。
我们通过form来定制下status这个字段的展示
# adminforms.py
from django import forms
class PostAdminForm(forms.ModelForm):
status = forms.BooleanField(label="是否删除", required=True)
desc = forms.CharField(widget=forms.Textarea, label='摘要', required=False)
# admin.py
from .adminforms import PostAdminForm
form = PostAdminForm
五、同时编辑外键和数据Inline
class PostInlineAdmin(admin.TabularInline):
fields = ('title', 'status')
extra = 1 # 控制额外多几个
min_num = 1
model = Post
class CategoryAdmin(admin.ModelAdmin):
inlines = [
PostInlineAdmin
]
六、抽象基础Admin类
在日常开发中经常会有遇到这样的问题,同样的代码亦或是类似的逻辑遍布在项目各处,可能是之前有人通过copy完成的业务功能,也可能是自己编写,恰巧逻辑一样。不管怎么说,这样的代码会导致维护成本的提高。试想一下,如果有一天,这样的逻辑需要修改,那你要修改多少个地方?就算你是维护这个项目很久的“老人”,也可能会输出,遗漏一两处,进而导致线上故障。
所以在开发时我们要时刻保持的理念是——尽量降低后期的维护成本。如何降低呢?自然是降低负担,让后来的程序员在修改代码时不会被之前凌乱的代码“绊倒”。
话不多说,我们先来抽象出一个基类——BaseOwnerAdmin,这个类需要帮忙我们完成两件事:一、重写save方法,save时设置对象的owner;二、重写get_queryset方法,这样让列表页在展示文章或者分类时只能展示当前用户的数据。
# -*- coding:utf-8 -*-
from __future__ import unicode_literals
__author__ = 'cao.yh'
__date__ = '2018/4/5 下午12:02'
from django.contrib import admin
class BaseOwnerAdmin(admin.ModelAdmin):
"""
针对有Owner属性的数据(文章、分类、标签、侧边栏、友链),重写
1. save_model - 保证每一条数据都属于当前用户
2. get_queryset - 保证每个用户只能看到自己的文章
"""
# 此方法为admin界面显示所有可编辑的Model实例
def get_queryset(self, request):
qs = super(BaseOwnerAdmin, self).get_queryset(request)
if request.user.is_superuser:
return qs
return qs.filter(owner=request.user)
# 此方法为admin界面用户保存Model实例时的行为:request为HttpRequest实例,obj为model实例,form为ModelForm实例,change为bool值,取决于model实例是新增的还是修改的。
def save_model(self, request, obj, form, change):
obj.owner = request.user # 把request.user保存为model实例的属性
return super(BaseOwnerAdmin, self).save_model(request, obj, form, change)
遇到的问题
ERRORS: (admin.E108) The value of 'list_display[3]' refers to 'category', which is not a callable, an attribute of 'PostAdmin', or an attribute or method on 'blog.Post'.
System check identified 1 issue (0 silenced).
解决办法:查看PostAdmin中list_display中相关字段的拼写
参考:
https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_queryset
https://docs.djangoproject.com/en/1.11/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_model