github链接 https://github.com/yt-xy/Django-blog
优化Admin管理后台
自定义过滤器只展示当前用户分类
SimpleListFilter类提供了两个属性和两个方法供我们重写。title用于展示标题,parameter_name就是查询时URL参数的名字。
lookups:返回要展示的内容和查询用的id
queryset:根据URL Query的内容返回列表页数据
blogs/admin.py
class CategoryOwnerFilter(admin.SimpleListFilter):
"""自定义过滤器只展示当前用户分类"""
title = '分类过滤器'
parameter_name = 'owner_category'
def lookups(self, request, model_admin):
return Category.objects.filter(owner=request.user).values_list('id', 'name')
def queryset(self, request, queryset):
category_id = self.value()
if category_id:
return queryset.filter(category_id=self.value())
return queryset
# 修改PostAdmin
list_filter = [CategoryOwnerFilter]
让当前登录的用户在列表页只能看到自己创建的文章
blogs/admin.py
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = [
'title', 'category', 'status',
'created_time', 'owner', 'operator'
]
...
def get_queryset(self, request):
qs = super(PostAdmin, self).get_queryset(request)
return qs.filter(owner=request.user)
字段展示
对于字段是否展示以及展示顺序的需求,可以通过fields或者fieldset来配置,通过exclude可以指定哪些字段是不展示的。
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = [
'title', 'category', 'status',
'created_time', 'owner', 'operator'
]
...
exclude = ('owner', )
fields = (
('category', 'title'),
'desc',
'status',
'content',
'tag',
)
fieldsets用来控制页面布局,要求格式是有两个元素的tuple的list
fieldsets = (
(名称, {内容}),
(名称, {内容}),
)
其中包含两个元素的tuple内容,第一个元素是当前版块的名称,第二个元素是当前版块的描述、字段和样式配置
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
...
exclude = ('owner', )
fieldsets = ( # 替换fields
('基础配置', {
'description': '基础配置描述',
'fields': (
('title', 'category'),
'status',
),
}),
('内容', {
'fields': (
'desc',
'content',
),
}),
('额外信息', {
'classes': ('collapse', ),
'fields': ('tag', ),
})
)
针对多对多字段展示的配置还有filter_horizontal
和filter_vertical
,一个是横向展示,一个是纵向展示
filter_horizontal = ('tag', )
# filter_vertical = ('tag', )
自定义静态资源引入
对于Django自动生成的页面如何自定义class来控制页面元素样式呢?
可以通过自定义Media类在页面上添加想要的JavaScript以及CSS资源
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
...
class Media:
css = {
'all': ("https://cdn.bootcss.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css", ),
}
js = ('https://cdn.bootcss.com/bootstrap/4.0.0-beta.2/js/bootstrap.bundle.js', )
自定义Form
这边的自定义Form是用作后台管理的Form,不是前台针对用户输入进行处理的Form
blogs/adminforms.py
from django import forms
# 后台管理的forms
class PostAdminForm(forms.ModelForm):
desc = forms.CharField(widget=forms.Textarea, label='摘要', required=False)
blogs/admin.py
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
form = PostAdminForm
...
在同一页面编辑关联数据
需求:在分类页面直接编辑文章[对于需要在一个页面内完成两个关联模型编辑的需求,使用inline admin方式非常合适]
blogs/admin.py
class PostInline(admin.TabularInline): # StackedInline样式不同
fields = ('title', 'desc')
extra = 1 # 控制额外多几个
model = Post
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
inlines = [PostInline, ]
...
定制site
大部分情况下,只需要一个site就够了,一个site对应一个站点,这就像上面所有操作最终都反应在一个后台。当然,我们也可以通过定制site来实现系统对外提供多套admin后台的逻辑。
需求:用户模块的管理应该和文章等数据的管理分开
blog/blog/custom_site.py
from django.contrib.admin import AdminSite
class CustomSite(AdminSite):
site_header = 'Blog'
site_title = 'Blog管理后台'
index_title = '首页'
custom_site = CustomSite(name='cus_admin')
所有App下的admin.py
@admin.register(Post)
修改为@admin.register(Post, site=custom_site)
再加上from blog.custom_site import custom_site
因为blogs/admin.py中使用了reverse方式来获取后台地址,其中使用了admin,所以reverse('admin:blogs_post_change', args=(obj.id,))
需要调整为
reverse('cus_admin:blogs_post_change', args=(obj.id,))
urls.py
from django.conf.urls import url
from django.contrib import admin
from blog.custom_site import custom_site
urlpatterns = [
# path('admin/', admin.site.urls),
url(r'^super_admin/', admin.site.urls),
url(r'^admin/', custom_site.urls)
]