运行系统尝试添加用户并添加数据,出现的效果
可以看到当前登录的用户虽然是DOCTOR,但依然可以看到其他用户的文章,而且过滤器上也展示了非当前用户创建的分类,显然这是一个需要我们解决的问题.
首先解决右侧过滤器的功能,这时需要自定义过滤器,这里贴上文档中的说明
接下来我们就来编写自定义过滤器的代码:
1 class CategoryOwnerFilter(admin.SimpleListFilter): 2 """自定义过滤器只展示当前用户分类""" 3 4 title = ‘分类过滤器‘ # 标题 5 parameter_name = ‘owner_category‘ # 查询时URL参数的名字 6 7 def lookups(self, request, model_admin): # 返回要展示的内容和查询用的id 8 return Category.objects.filter(owner=request.user).values_list(‘id‘, ‘name‘) 9 10 def queryset(self, request, queryset): 11 category_id = self.value() 12 if category_id: 13 return queryset.filter(category_id=self.value()) 14 return queryset
CategoryOwnerFilter
parameter_name是在查询时的URL的参数名,
我们的过滤器可以通过这个参数来进行过滤.
lookups是我们展示在页面的内容,以及查询用的id
比如我点击 DOCTOR的Django分类 时,那么就会调用queryset方法,self.value()就是我们lookups中设置的查询用的id,在这里我的分类的id是3,所以传进来的参数也是3.
在代码编写完成后,记得要把PostAdmin中的过滤器改为
1 list_filter = [CategoryOwnerFilter] # 页面过滤器
自定义列表页数据
接下来我们要让登录的用户在列表页中只能看到自己创建的文章.
我们需要重写get_queryset方法(我在文档中没有找到这一项的说明,但不管怎样,看它的名字我们就知道它返回的是一个QuerySet对象,那么我们就可以使用filter来进行过滤!这样就可以实现我们想要的效果了.)
1 def get_queryset(self, request): 2 qs = super(PostAdmin, self).get_queryset(request) 3 return qs.filter(owner=request.user)
接下来进行编辑页面的配置.
首先我们得明确在编辑页面中有哪些东西是可以被定制的,比如:
l 按钮位置
l 哪些字段需要被用户填写,哪些不用填写甚至不用展示
l 页面的字段展示顺序是不是能被调整,展示位置是否能被调整
l 输入框的样式
按钮的位置用 save_on_top来控制是否在页面顶部展示按钮
对于字段是否展示以及展示顺序,可以通过fields或者fieldsets来配置
1 fields = ( 2 (‘category‘, ‘title‘), 3 ‘desc‘, 4 ‘status‘, 5 ‘content‘, 6 ‘tag‘, 7 )
再试试用fieldsets替换fields:
fieldsets的格式要求有两个元素的tuple的list,例如
1 fieldsets = ( 2 (名称, {内容}), 3 (名称, {内容}), 4 )
修改后的fieldsets;
1 fieldsets = ( 2 (‘基础配置‘, { 3 ‘description‘: ‘基础配置描述‘, 4 ‘fields‘: ( 5 (‘title‘, ‘category‘), 6 ‘status‘, 7 ), 8 }), 9 (‘内容‘, { 10 ‘description‘: ‘摘要默认选取内容中的前140个字‘, 11 ‘fields‘: ( 12 ‘desc‘, 13 ‘content‘, 14 ), 15 }), 16 (‘额外信息‘, { 17 ‘classes‘: (‘collapse‘, ), 18 ‘fields‘: (‘tag‘, ), 19 }), 20 )
fieldsets
页面效果:
fields的配置效果就跟原本的fields效果是一样的.
classes的作用是给要配置的板块加上一些CSS属性,Django admin默认支持collapse和wide.
description显然是板块的描述.
自定义静态资源引入
Django给我们提供了接口来添加css和js:
1 class Media: 2 css = { 3 ‘all‘: ("https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.min.css", ), 4 } 5 js = ("https://cdn.bootcss.com/twitter-bootstrap/4.4.0/js/bootstrap.bundle.js", )
自定义Form
以上的配置都是基于ModelAdmin的,如果我们有更多的定制需求,应该使用ModelForm,在blogApp中新建一个adminforms.py文件,我们要定制desc这个字段的展示,可以这样写
1 from django import forms 2 3 4 class PostAdminForm(forms.ModelForm): 5 desc = forms.CharField(widget=forms.Textarea, label=‘摘要‘, required=False)
配置到PostAdmin中
1 form = PostAdminForm
可以看到摘要已经改为Textarea组件了
定制site
我们可以通过定制site来实现一个系统对外提供多套admin后台的逻辑.在我们原本的页面中,文章分类等数据的管理与用户管理是在一起的,这样看着其实挺别扭,对于功能上来说也不合适,所以我们来把它们分开.
我们之前使用的django提供的admin.site模块,这里面的site其实是django.contrib.admin.AdminSite的一个实例,我们通过继承来定义自己的site,代码如下:
1 from django.contrib.admin import AdminSite 2 3 4 class CustomSite(AdminSite): 5 site_title = ‘Blog管理后台‘ 6 site_header = ‘Blog‘ 7 index_title = ‘首页‘ 8 9 10 custom_site = CustomSite(name=‘cus_admin‘)
在Blog目录下新建一个custom_site.py文件,把代码贴上去,接下来修改所有App的admin中的register.
1 @admin.register(Category, site=custom_site)
在我们的PostAdmin中,我们自定义了一个operator方法,因为把site模块改为了自定义的模块,所以reverse中的名称也需要修改
1 def operator(self, obj): 2 return format_html( 3 ‘<a href="{}">编辑</a>‘, 4 reverse(‘cus_admin:blogApp_post_change‘, args=(obj.id,)) 5 )
最后在urls.py中添加路由
1 urlpatterns = [ 2 path(‘admin/‘, custom_site.urls), 3 path(‘super_admin/‘, admin.site.urls), 4 ]
这样就有了两套后台地址.要注意的是这两套系统都是基于一套逻辑的用户系统,只是我们在URL上进行了划分.
抽取Admin基类
在我们的admin中,我们重写了save_model方法和get_queryset方法,这就让我们的代码有很多重复,质量很差,可以通过继承来使代码变得简洁.
抽象出一个基类BaseOwnerAdmin
1 from django.contrib import admin 2 3 4 class BaseOwnerAdmin(admin.ModelAdmin): 5 exclude = (‘owner‘, ) 6 7 def get_queryset(self, request): 8 qs = super(BaseOwnerAdmin, self).get_queryset(request) 9 return qs.filter(owner=request.user) 10 11 def save_model(self, request, obj, form, change): 12 obj.owner = request.user 13 return super(BaseOwnerAdmin, self).save_model(request, obj, form, change)
把它放到Blog目录下的base_admin.py文件中,把App的admin中的继承改为BaseOwnerAdmin即可.
最后还有添加查看操作日志功能.
1 @admin.register(LogEntry, site=custom_site) 2 class LogEntryAdmin(admin.ModelAdmin): 3 list_display = [‘object_repr‘, ‘object_id‘, ‘action_flag‘, ‘user‘, ‘change_message‘]
之后开始开发面向用户的界面.
原文地址:https://www.cnblogs.com/ylnx-tl/p/12613263.html