xadmin的使用
01-下载源码
GitHub地址:https://github.com/sshwsfc/xadmin
# 安装xadmin 由于使用的是Django2.0的版本,所以需要安装xadmin项目django2分支的代码。 在PyCharm里打开命令行工具,输入以下命令完成安装: pip install git+git://github.com/sshwsfc/xadmin.git@django2 也可以使用https的地址安装,命令如下: pip install git+https://github.com/sshwsfc/xadmin.git@django2
02-配置settings.py
# 引入下面三个app INSTALLED_APPS = [ .... 'xadmin', 'crispy_forms', 'reversion', ] # 修改使用中文界面 LANGUAGE_CODE = 'zh-Hans' # 修改时区 TIME_ZONE = 'Asia/Shanghai' ALLOWED_HOSTS = ['*', ]
03-配置路由
# urls.py # -*- coding: utf-8 -*- # from django.conf.urls import include, url from django.urls import include, path # Uncomment the next two lines to enable the admin: import xadmin xadmin.autodiscover() # version模块自动注册需要版本控制的 Model from xadmin.plugins import xversion xversion.register_models() from django.contrib import admin urlpatterns = [ path(r'xadmin/', xadmin.site.urls) ]
04-创建数据库
python manage.py makemigrations
python manage.py migrate
05-创建超级用户
python manage.py createsuperuser
06-拉取静态文件到本地
python manage.py collectstatic
07-站点Model管理
xadmin 可以使用的页面样式控制基本与Django原生的admin一直。 list_display 列表展示的字段 preserve_filters 默认情况下,当你对目标进行创建、编辑或删除操作后,页面会依然保持原来的过滤状态。将preserve_filters设为False后,则会返回未过滤状态。 prepopulated_fields 设置预填充字段。不接收DateTimeField、ForeignKey和ManyToManyField类型的字段。 view_on_site 这个属性可以控制是否在admin页面显示“View site”的链接。这个链接主要用于跳转到你指定的URL页面。 free_query_filter 属性: 默认为 True , 指定是否可以自由搜索. 如果开启自由搜索, 用户可以通过 url 参数来进行特定的搜索, search_fields 可以通过搜索框搜索的字段名称,xadmin使用的是 模糊查询,存在外键 同 list_filter 一样 注意:只能包括 字符类型,不能有 非字符类型 如:SBBH-20180515-0002 list_filter 可以进行过滤操作的列,例如:存在外键字段class ---》student__class 获取值 ordering 默认排序的字段 readonly_fields 在编辑页面的只读字段 exclude 在编辑页面隐藏的字段 list_editable 在列表页可以快速直接编辑的字段 show_detail_fileds 在列表页显示详情信息 refresh_times 指定列表页的数据定时刷新 例如:refresh_times=(3,5) list_export 控制列表页导出数据的类型 show_bookmarks 控制是否显示书签功能 data_charts 控制显示图标的样式 model_icon 配置表的图标,可以在 awesome 上下载最新的font-awesome.css 替换,并寻找相应的icon书写 fieldsets ,详细页面时,使用fieldsets标签对数据进行分割显示 empty_value_display = "列数据为空时,显示默认值" # 列聚合,可用的值:"count","min","max","avg", "sum" aggregate_fields = {"expire": "max"} # 显示还原按钮,删除修改的信息可以还原 reversion_enable = True # 添加数据时候,一步一步提供数据 wizard_form_list = [ ("基础信息", ("name", "contact", "telphone", "address")), ("其它信息", ("customer_id", "expire", "description")), ] fields 表单显示内容, 不包含在内的字段不能编辑 filter_horizontal 从‘多选框’的形式改变为‘过滤器’的方式,水平排列过滤器,必须是一个 ManyToManyField类型,且不能用于 ForeignKey字段,默认地,管理工具使用下拉框 来展现外键 字段 raw_id_fields 将ForeignKey字段从‘下拉框’改变为‘文本框’显示 relfield_style 后台自定义不是下拉选择框,而是搜索框(解决了为什么用户不是下拉框的问题。。) relfield_style = 'fk-ajax' exclude 在编辑和查看列表时指定不显示的字段 list_editable 列表显示的时候,指定的字段可以直接页面一键编辑 list_display_links 设置默认可编辑字段 list_per_page = 20 每页显示20个 actions = ('ocr_action', 'excel_action', 'auto_excel_action') 在类中自定义的函数方法 auto_excel_action.short_description='自动化导入数据文件' 函数名描述 object_list_template = "test.html" 自定义页面 data_charts 图表,该属性为dict类型,key为图表的标示名称,value为图表的具体设置属性 data_charts = { "user_count": {'title': u"约运动", "x-field": "sport_time", "y-field": ("people_nums",), }, } 图表属性: title : 图表的显示名称 x-field : 图表的 X 轴数据列, 一般是日期, 时间等 y-field : 图表的 Y 轴数据列, 该项是一个 list, 可以同时设定多个列, 这样多个列的数据会在同一个图表中显示 order : 排序信息, 如果不写则使用数据列表的排序 # 导出类型 list_export = ('xls', 'xml', 'json') list_export设置为None来禁用数据导出功能 #导出字段 list_export_fields = ('start_people', 'sport', 'sport_time')
# adminx.py class CashTitleContentAdmin(object): # 菜单的图标 model_icon = 'fa fa-image' # 列表显示内容 list_display = ('subtitle', 'content_cash', ) # list_display_links 设置默认可编辑字段 list_display_links = ('subtitle', ) # # 分页显示 # list_per_page = settings.list_per_page # 过滤器 list_filter = ('content_cash',) # 表单显示内容 fields = ('subtitle', 'content_cash', ) # 搜索字段 search_fields = ('subtitle', 'content_cash__title', ) xadmin.site.register(cash_title_content, CashTitleContentAdmin)
08-站点的全局配置
# settingx/adminx.py import xadmin from xadmin import viewsclass BaseSetting(object): """xadmin的基本配置""" enable_themes = True # 开启主题切换功能 use_bootswatch = True # 支持切换主题 xadmin.site.register(views.BaseAdminView, BaseSetting) class GlobalSettings(object): """xadmin的全局配置""" site_title = "xxx后台管理系统" # 设置站点标题 site_footer = "xxxxxxx" # 设置站点的页脚 menu_style = "accordion" # 设置菜单折叠,在左侧,默认的 # 设置models的全局图标, UserProfile, Sports 为表名 global_search_models = [UserProfile, Sports] global_models_icon = { UserProfile: "glyphicon glyphicon-user", Sports: "fa fa-cloud" xadmin.site.register(views.CommAdminView, GlobalSettings)
09-app名称的修改
# app名为users下的apps.py from django.apps import AppConfig class UsersConfig(AppConfig): # 设置app图标 app_icon = 'fa fa-line-chart' # app名 name = 'users' verbose_name = u'用户管理' # __init__.py default_app_config='users.apps.UsersConfig'
10-自定义导航菜单顺序
from xadmin import views class GlobalSetting(object): def get_site_menu(self): return ( {'title': '课程管理', 'menus': ( {'title': '课程信息', 'url': self.get_model_url(Course, 'changelist')}, {'title': '章节信息', 'url': self.get_model_url(Lesson, 'changelist')}, {'title': '视频信息', 'url': self.get_model_url(Video, 'changelist')}, {'title': '课程资源', 'url': self.get_model_url(CourseResource, 'changelist')}, {'title': '课程评论', 'url': self.get_model_url(CourseComments, 'changelist')}, )}, {'title': '机构管理', 'menus': ( {'title': '所在城市', 'url': self.get_model_url(CityDict, 'changelist')}, {'title': '机构讲师', 'url': self.get_model_url(Teacher, 'changelist')}, {'title': '机构信息', 'url': self.get_model_url(CourseOrg, 'changelist')}, )}, {'title': '用户管理', 'menus': ( {'title': '用户信息', 'url': self.get_model_url(UserProfile, 'changelist')}, {'title': '用户验证', 'url': self.get_model_url(EmailVerifyRecord, 'changelist')}, {'title': '用户课程', 'url': self.get_model_url(UserCourse, 'changelist')}, {'title': '用户收藏', 'url': self.get_model_url(UserFavorite, 'changelist')}, {'title': '用户消息', 'url': self.get_model_url(UserMessage, 'changelist')}, )}, {'title': '系统管理', 'menus': ( {'title': '用户咨询', 'url': self.get_model_url(UserAsk, 'changelist')}, {'title': '首页轮播', 'url': self.get_model_url(Banner, 'changelist')}, {'title': '用户分组', 'url': self.get_model_url(Group, 'changelist')}, {'title': '用户权限', 'url': self.get_model_url(Permission, 'changelist')}, {'title': '日志记录', 'url': self.get_model_url(Log, 'changelist')}, )}, xadmin.site.register(views.CommAdminView, GlobalSetting)
11-设置只读字段
在使用xadmin的时候,ModelAdmin默认只有对于model的增删改查,但是总是有些字段是不希望用户来编辑的。而 readonly_fields 设置之后不管是admin还是其他用户都会变成只读,而我们通常只是想限制普通用户。 这时我们就可以通过重写 get_readonly_fields 方法来实现对特定用户的只读显示。
class UserInfoAdmin(): def get_readonly_fields(self, **kwargs): """ 重新定义此函数,限制普通用户所能修改的字段 """ print(self.org_obj) if self.user.is_superuser: self.readonly_fields = [] return self.readonly_fields readonly_fields = ('user_email',)
12-在list_display显示自定义函数:
list_display = ['get_chapter_num'] # 需要在自定义的函数下加上如下内容 def get_chapter_num(self): return self.chapter_set.all().count() get_chapter_num.short_description= '章节数'
13-设置页面跳转,需自定义函数
def go_to(self): # 设置列表页跳转 from django.utils.safestring import mark_safe return mark_safe('<a href="http://www.fishc.com.cn">跳转</a>') go_to.short_description = '友情链接'
14-如果想添加数据的同时方便添加关联model:inlines 机制 同一个页面 可以添加 所有的相关信息
class ChapterInline: model = Chapter extra = 0
在CoursesXadmin 添加 inlines = [ChapterInline]
15-重载显示样式
from xadmin.layout import Main,Fieldset,Row,Side def get_form_layout(self): if self.org_obj: self.form_layout = ( Main( Fieldset('', 'username', 'password', css_class='unsort no_title' ), Fieldset(_('Personal info'), Row('first_name', 'last_name'), # 显示在一行 'email' ), Fieldset(_('Permissions'), 'groups', 'user_permissions' ), Fieldset(_('Important dates'), 'last_login', 'date_joined' ), ), Side( Fieldset(_('Status'), 'is_active', 'is_staff', 'is_superuser', ), ) ) return super(UserAdmin, self).get_form_layout()子主题
页面的布局在xadmin/plugins/auth.py里的UserAdmin类,修改这个类里的get_form_layout函数,就可以修改布局
def get_form_layout(self): if self.org_obj: self.form_layout = ( #Fieldset表示一个区块 Main( Fieldset('', 'username', 'password', # 显示字段 css_class='unsort no_title' # css_class='unsort no_title'表示定位区块不能拖动 ), Fieldset(_('Personal info'), #Fieldset第一个参数表示区块名称 Row('first_name', 'last_name'), # Row 表示将里面的字段作为一行显示 'email', ), Fieldset(_('Permissions'), 'groups', 'user_permissions', ), Fieldset(_('Important dates'), 'last_login', 'date_joined', ), ), #Side表示状态区块 Side( Fieldset(_('Status'), 'is_active', 'is_staff', 'is_superuser', ), ) ) return super(UserAdmin, self).get_form_layout()
16-model的管理器,一个model 分不同情况 管理
class Course(models.Model): pass class BannerCourse(Course): # 继承 父类 course class Meta: verbose_name = '轮播课程' verbose_name_plural = verbose_name proxy = True # 不会生成新的表 # 注册新的表 class CourseSourceAdmin(object): list_display = ['course', 'name', 'add_time', 'download'] list_filter = ['course', 'name', 'add_time', 'download'] search_fields = ['course', 'name', 'download'] def queryset(self): qs = super(CourseAdmin, self).queryset() qs = qs.filter(is_banner=False) return qs
17-获取当前的user表model
from django.contrib.auth import get_user_model (获取当前的user表model) User = get_user_model() site.register(User,Useradmin)
18-卸载注册的model
from django.contrib.auth.models import User xadmin.site.unregister(User)
19-替换默认的注册 user(继承了abstractuser)
class UserInfoAdmin(object): list_display = ['auth', 'name', 'depart', 'email', 'username'] list_filter = ['auth', 'name', 'depart', 'email', 'username'] search_fields = ['auth', 'name', 'depart', 'email', 'username'] list_editable = ['auth', 'name', 'depart', 'email', 'username'] list_display_links = ['auth', 'name', 'depart', 'email', 'username'] model_icon = 'fa fa-user-circle-o' from django.contrib.auth import get_user_model # 获取当前的user_model xadmin.site.unregister(get_user_model()) # 注销 user xadmin.site.register(UserInfo,UserInfoAdmin) # 注册新的 user
20-表单根据用户显示不同的字段内容 get_model_form
import xadmin # Register your models here. from .models import User from xadmin.plugins import auth class UserAdmin(auth.UserAdmin): list_display = ['id', 'username', 'mobile', 'email', 'date_joined'] readonly_fields = ['last_login', 'date_joined'] search_fields = ('username', 'first_name', 'last_name', 'email', 'mobile') style_fields = {'user_permissions': 'm2m_transfer', 'groups': 'm2m_transfer'} # 表单根据用户显示不同的字段内容 def get_model_form(self, **kwargs): if self.org_obj is None: self.fields = ['username', 'mobile', 'is_staff'] return super().get_model_form(**kwargs) xadmin.site.unregister(User) xadmin.site.register(User, UserAdmin)
而在 admin 里是 get_fields
# 表单根据用户显示不同的字段内容 def get_fields(self, request, obj=None):
21-模型编辑页面Field分区显示--form_layout
在admin.py中我们可以通过Fieldsets去设置字段的分块显示,例如以下代码:
界面显示会上下分区,分为名字为空和名字为其它的两个区域。
class DeviceAdmin(admin.ModelAdmin): ... fieldsets = ( (None, { 'fields': ('site', 'device_name', 'device_id', 'device_type', 'account', 'password') }), ('其它', { 'fields': ('responsible_by', 'device_ip', 'device_model', 'sn_number', 'supplier', 'buy_date', 'expire_date', 'note', 'attachment', 'date'), }), )
而在xadmin.py中,这个字段不再生效,需用form_layout去设置。
可分为Main主区域和Side侧边区域,Main或Side中又可通过Fieldset再分多个区域。Fieldset为一个元组,第一个字段为需要设置的名称,其它字段均为模型中的字段名。如下:
class DeviceAdmin(object): ... form_layout = ( Main( Fieldset('基础信息', 'site', 'device_name', 'device_id', 'device_type', 'account', 'password'), Fieldset('EXTRA', 'device_model', 'supplier', 'responsible_by', 'device_ip', 'sn_number'), ), Side( Fieldset('其它', 'buy_date', 'expire_date', 'note', 'attachment', 'date'), ) )
22-获取用户信息并填充模型字段--save_models
有时模型中会需要记录添加数据的用户,保存在created_by这样的字段中。这时我们就需要重写save_model方法,在保存模型时存入用户的信息。
admin.py中会sava_model,如下。
class DeviceAdmin(admin.ModelAdmin): ... def save_model(self, request, obj, form, change): obj.area_company = Group.objects.get(user=request.user) super().save_model(request, obj, form, change)
而xadmin.py中改为使用save_models。
class DeviceAdmin(object): ... def save_models(self):
obj = self.new_obj self.new_obj.area_company = Group.objects.get(user=self.request.user) super().save_models()
23-根据登录用户或组过滤数据--queryset
需要根据登录用户或组过滤数据时,admin.py中是重写get_queryset方法,xadmin.py中改为重写queryset方法即可。如下:
class DeviceAdmin(object): ... def queryset(self): """函数作用:使当前登录的用户只能看到自己负责的设备""" qs = super(DeviceAdmin, self).queryset() if self.request.user.is_superuser: return qs return qs.filter(area_company=Group.objects.get(user=self.request.user))
# 用户管理 class UserManageAdmin(object): list_display = ['id', 'name','addtime','get_UserManage_Taocan' ] search_fields = ['name'] list_filter = ['phone',] ordering = ['-id'] # 进入xadmin页面将某个字段倒序排列 readonly_fields = ['addtime'] # 只读字段,不能编辑 # exclude = ['money'] # 不显示的字段 list_editable = ['name', ] # 即使编辑器 relfield_style = 'level' # 带有外键的字段变成搜索格式 model_icon = 'fa fa-user' # 表左边的图标 is_execute = True # 使用js插件 # 禁止页面批量删除 def has_delete_permission(self,*args,**kwargs): if args: return True return False # 自动添加管理员 def save_models(self): self.new_obj.user = self.request.user super().save_models() # 设置用户只能查看自己填写的数据 def queryset(self): qs = super(UserManageAdmin, self).queryset() if self.request.user.is_superuser: # 超级用户可查看所有数据 return qs else: que = qs.filter(user=self.request.user) return que
24-外键下拉框添加过滤
class DeviceAdmin(admin.ModelAdmin): ... def formfield_for_foreignkey(self, db_field, request, **kwargs): if not self.request.user.is_superuser: # 非superuser进行过滤,superuser可以看到全部 if db_field.name == "site": kwargs["queryset"] = Site.objects.filter(area_company=Group.objects.get(user=self.request.user)) return super(DeviceAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
而xadmin.py中没有这个方法了,需要重写formfield_for_dbfield方法。如下:
class DeviceAdmin(object): ... def formfield_for_dbfield(self, db_field, **kwargs): if not self.request.user.is_superuser: if db_field.name == "site": kwargs["queryset"] = Site.objects.filter(area_company=Group.objects.get(user=self.request.user)) return super(DeviceAdmin, self).formfield_for_dbfield(db_field, **kwargs)
25-后台显示模型类不存在的字段
需求如下:订单信息中显示商品,但是我们知道订单和订单中的商品是分开两个表储存的,通过外键关联起来。那如何在订单信息中显示所包含的商品呢?
一、在订单中再添加一个字段,保存该订单所有商品的简单信息。
二、不修改数据库字段,而是在后台显示时多显示一字段(显示改订单的所有商品的基本信息)
第二种方法的代码如下:自定义一个显示字段(get_goods),该字段必须为只读(readonly_fields)才会显示出来。
class OrdersAdminModel(object): def get_goods(self,obj): goods_queryset = obj.ordergoods_set.all() return str(["商品%s:%s 单价:%s 元"%(i.goods.id,i.goods.name,i.goods.price) for i in goods_queryset]) get_goods.short_description = '购买的商品' list_display = ['order_id','user','status','get_goods'] readonly_fields = ("order_id",'get_goods')
26-django自带的admin是有save_models和delete_model的,后台修改模型类后就会执行改函数,xadmin中如下
def save_models(self): # 新的对象 obj = self.new_obj # 可以在这里面写些逻辑 # 保存该对象 obj.save() def delete_model(self): # 删除数据对象 obj = self.obj # 相应的操作 obj.delete()
27-定制HTML模板
add_form_template = None change_form_template = None change_list_template = None delete_confirmation_template = None delete_selected_confirmation_template = None object_history_template = None
28-xadmin此版本貌似不能加载views.py
作为破解在 __init__.py中增加了 import views一行,如下:
__init__.py
import views
29-列表视图新增自定义按钮
https://www.cnblogs.com/Tommy-Yu/p/5443127.html
http://www.cnblogs.com/livingintruth/p/3738601.html
30-自定义actions
1. 首先要创建一个 Action 类, 该类需要继承 BaseActionView. BaseActionView 是 ModelAdminView 的子类: from xadmin.plugins.actions import BaseActionView class MyAction(BaseActionView): # 这里需要填写三个属性 action_name = "my_action" #: 相当于这个 Action 的唯一标示, 尽量用比较针对性的名字 description = _(u'Test selected %(verbose_name_plural)s') #: 描述, 出现在 Action 菜单中, 可以使用 ``%(verbose_name_plural)s`` 代替 Model 的名字. model_perm = 'change' #: 该 Action 所需权限 # 而后实现 do_action 方法 def do_action(self, queryset): # queryset 是包含了已经选择的数据的 queryset for obj in queryset: # obj 的操作 ... # 返回 HttpResponse return HttpResponse(...) 2. 然后在 Model 的 OptionClass 中使用这个 Action: class MyModelAdmin(object): actions = [MyAction, ] 3. 这样就完成了自己的 Action。
31-给这个方法添加一个boolean的属性并赋值为True,它将显示为on/off的图标
from django.db import models from django.contrib import admin class 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 = True class PersonAdmin(admin.ModelAdmin): # 官方文档这里有错,将'name'改为'first_name' list_display = ('first_name', 'born_in_fifties')
32-屏蔽界面的添加按钮
33-xadmin列表页添加自定义工具栏toolbar
https://blog.csdn.net/iteye_12715/article/details/82678755
34-想对某些字段设置颜色,可用下面的设置
from django.db import models from django.contrib import admin from django.utils.html import format_html class 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')
35-菜单分组管理
https://www.cnblogs.com/fiona-zhong/p/9647986.html
36-自定义函数作为 列 显示
# models.py class Course(models.Model): ' ' ' def get_zj_nums(self): #获取课程的章节数 return self.lesson_set.all().count() get_zj_nums.short_description = '章节数' #在后台显示的名称
# adminx.py class CourseAdmin(object): list_display = ['get_zj_nums'] # 直接使用函数名作为字段显示
效果如下:
37-增加页面显示的列 ‘跳转’——显示自定义的html代码
# models.py class Course(models.Model): . . . def go_to(self): from django.utils.safestring import mark_safe #mark_safe后就不会转义 return mark_safe("<a href='https://home.cnblogs.com/u/derek1184405959/'>跳转</a>") go_to.short_description = "跳转"
# adminx.py class CourseAdmin(object): list_display = ['go_to']
效果如下:
38-xadmin主页布局的修改
例如:
数据库是 MySQL,xadmin自带的两张表:xadmin_usersettings、xadmin_userwidget
xadmin_usersettings:字段value的初始值应为 | ,代表将主页面分为两列。
xadmin_userwidget:记录当前登录用户主页面 显示的小组件。
class Dashboard(CommAdminView): widget_customiz = True widgets = [] title = _(u"Dashboard") icon = None def get_page_id(self): return self.request.path def get_portal_key(self): return "dashboard:%s:pos" % self.get_page_id() @filter_hook def get_widget(self, widget_or_id, data=None): try: if isinstance(widget_or_id, UserWidget): widget = widget_or_id else: widget = UserWidget.objects.get(user=self.user, page_id=self.get_page_id(), id=widget_or_id) wid = widget_manager.get(widget.widget_type) class widget_with_perm(wid): def context(self, context): super(widget_with_perm, self).context(context) context.update({'has_change_permission': self.request.user.has_perm('xadmin.change_userwidget')}) wid_instance = widget_with_perm(self, data or widget.get_value()) return wid_instance except UserWidget.DoesNotExist: return None @filter_hook def get_init_widget(self): portal = [] widgets = self.widgets for col in widgets: portal_col = [] for opts in col: try: widget = UserWidget(user=self.user, page_id=self.get_page_id(), widget_type=opts['type']) widget.set_value(opts) widget.save() portal_col.append(self.get_widget(widget)) except (PermissionDenied, WidgetDataError): widget.delete() continue portal.append(portal_col) UserSettings( user=self.user, key="dashboard:%s:pos" % self.get_page_id(), value='|'.join([','.join([str(w.id) for w in col]) for col in portal])).save() return portal @filter_hook def get_widgets(self): if self.widget_customiz: portal_pos = UserSettings.objects.filter( user=self.user, key=self.get_portal_key()) if len(portal_pos): portal_pos = portal_pos[0].value widgets = [] if portal_pos: user_widgets = dict([(uw.id, uw) for uw in UserWidget.objects.filter(user=self.user, page_id=self.get_page_id())]) for col in portal_pos.split('|'): ws = [] for wid in col.split(','): try: widget = user_widgets.get(int(wid)) if widget: ws.append(self.get_widget(widget)) except Exception as e: import logging logging.error(e, exc_info=True) widgets.append(ws) return widgets return self.get_init_widget() @filter_hook def get_title(self): return self.title @filter_hook def get_context(self): new_context = { 'title': self.get_title(), 'icon': self.icon, 'portal_key': self.get_portal_key(), 'columns': [('col-sm-%d' % int(12 / len(self.widgets)), ws) for ws in self.widgets], 'has_add_widget_permission': self.has_model_perm(UserWidget, 'add') and self.widget_customiz, 'add_widget_url': self.get_admin_url('%s_%s_add' % (UserWidget._meta.app_label, UserWidget._meta.model_name)) + "?user=%s&page_id=%s&_redirect=%s" % (self.user.id, self.get_page_id(), urlquote(self.request.get_full_path())) } context = super(Dashboard, self).get_context() context.update(new_context) return context @never_cache def get(self, request, *args, **kwargs): self.widgets = self.get_widgets() return self.template_response('xadmin/views/dashboard.html', self.get_context()) @csrf_protect_m def post(self, request, *args, **kwargs): if 'id' in request.POST: widget_id = request.POST['id'] if request.POST.get('_delete', None) != 'on': widget = self.get_widget(widget_id, request.POST.copy()) widget.save() else: try: widget = UserWidget.objects.get( user=self.user, page_id=self.get_page_id(), id=widget_id) widget.delete() try: portal_pos = UserSettings.objects.get(user=self.user, key="dashboard:%s:pos" % self.get_page_id()) pos = [[w for w in col.split(',') if w != str( widget_id)] for col in portal_pos.value.split('|')] portal_pos.value = '|'.join([','.join(col) for col in pos]) portal_pos.save() except Exception: pass except UserWidget.DoesNotExist: pass return self.get(request) @filter_hook def get_media(self): media = super(Dashboard, self).get_media() + \ self.vendor('xadmin.page.dashboard.js', 'xadmin.page.dashboard.css') if self.widget_customiz: media = media + self.vendor('xadmin.plugin.portal.js') for ws in self.widgets: for widget in ws: media = media + widget.media() return media
39-设置xadmin新用户主页的默认布局
数据库:
# xadmin/model.py @python_2_unicode_compatible class UserSettings(models.Model): user = models.ForeignKey(AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_(u"user")) key = models.CharField(_('Settings Key'), max_length=256) value = models.TextField(_('Settings Content')) # 重写save方法 def save(self, force_insert=False, force_update=False, using=None, update_fields=None): if not self.value: self.value = "|" super(UserSettings, self).save() page_id = 'home' default_list = [ [{'list': '{"title": "", "model": "auth.user"}'}, ], [{'list': '{"title": "", "model": "cashflows.bank_cash_flows"}'}, ], [{'html': '{"title": "Test Widget", "content": "第一次测试!!"}'}, ], [{'qbutton': '{"title": "aaa"}'}, ], ] for i in default_list: user_widget = UserWidget() for j in i: for z in j.keys(): user_widget.page_id = page_id user_widget.user_id = self.user_id user_widget.widget_type = z user_widget.value = j[z] user_widget.save() id_list = [] # 存放user的id a = UserWidget.objects.filter(user_id=self.user) for i in a: id_list.append(i.id) self.value = "%s,%s|%s,%s" % (id_list[0], id_list[1], id_list[2], id_list[3]) UserSettings.objects.filter(user_id=self.user).value = self.value super(UserSettings, self).save() else: super(UserSettings, self).save()
40. 根据登录用户user过滤展示数据(list_diaplay)
增加case_username字段,外键User表,新创建的数据与当前登录用户相关联!
# models.py class case_manage(models.Model): case_id = models.CharField(max_length=18, verbose_name=u'案件编号') case_name = models.CharField(max_length=50, verbose_name=u'案件名称') case_type = models.CharField(max_length=20, verbose_name=u'案件类别', blank=True, null=True) case_unit = models.CharField(max_length=20, verbose_name=u'办案单位', blank=True, null=True) case_desc = models.CharField(max_length=255, verbose_name=u'案件描述', blank=True, null=True) case_people = models.CharField(max_length=20, verbose_name=u'联系人姓名') case_tel = models.CharField(max_length=20, verbose_name=u'联系人电话', blank=True, null=True) case_time = models.DateTimeField(verbose_name=u'创建时间', default=timezone.now) case_username = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='创建人', editable=False, null=True, blank=True) class Meta: verbose_name = u'案件管理' verbose_name_plural = verbose_name db_table = 'case_manage' def operate_btn(self): # 操作 return mark_safe("<a href='/xadmin/cashflows/lead_case/'>查看账单</a>" " <a href='/xadmin/cashflows/lead_case/add/'>导入账单</a>") operate_btn.short_description = "操作"def __unicode__(self): return self.case_id def __str__(self): return self.case_id
问题:如果仅允许登录用户查看其自己创建的case_manage数据,该怎么处理?
增加queryset方法:如果是超级用户就可以看全部数据,不是的话,只能显示当前登录用户创建的数据。
def queryset(self): qs = super(CaseManageAdmin, self).queryset() if self.request.user.is_superuser: return qs else: return qs.filter(case_username=self.request.user)
# adminx.py class CaseManageAdmin(object): # 列表显示内容 list_display = ['case_id', 'case_name', 'case_desc', 'case_time', 'operate_btn', 'case_username'] # 设置默认可编辑字段 list_display_links = ['case_id', ] # 过滤器 list_filter = ['case_name', ] # 表单显示内容 fields = ['case_name', 'case_type', 'case_unit', 'case_desc', 'case_people', 'case_tel', 'case_time', ] # 搜索字段 search_fields = ['case_name', 'case_type', 'case_unit', 'case_desc', 'case_people', 'case_tel', 'case_time'] # 在编辑页面的只读字段 readonly_fields = ['case_time', ] actions = ['case_sum', ] def save_models(self): print(self.user.username) obj = self.new_obj if not obj.case_id: obj.case_id = DBHelper.get_id('case_manage', 'CASE') if not obj.case_username: obj.case_username = User.objects.get(username=self.user.username) obj.save() def queryset(self): qs = super(CaseManageAdmin, self).queryset() if self.request.user.is_superuser: return qs else: return qs.filter(case_username=self.request.user) def case_sum(self, request, queryset): pass case_sum.short_description = "合并案件" xadmin.site.register(case_manage, CaseManageAdmin)
增加上述方法后,还需要改变IDCAdmin的注册方式,之前使用的是注解注册方式:
@xadmin.sites.register(case_manage)
class CaseManageAdmin(object):
这种注册方式,不支持queryset方法,在xadmin系统里,点击“案件管理”菜单,会报错误;
应使用这种方式:xadmin.site.register(case_manage, CaseManageAdmin)
41. admin_order_field
支持查询查找以按相关模型上的值排序。此示例在列表显示中包含“作者名字”列,并允许按名字对其进行排序:
https://docs.djangoproject.com/en/1.8/ref/contrib/admin/
42. 获取verbose_name
UserInfo._meta.get_field('name').verbose_name
43. xadmin list_filter 外键显示含有英文,怎么把英文去掉?
# xadmin/plugins/filters.py # 在这个文件里,第126行 # if len(field_parts) > 1: # # Add related model name to title # spec.title = "%s %s" % (field_parts[-2].name, spec.title) # 注释掉!
45. 添加自定义的URL
https://www.cnblogs.com/fangsheng/p/9783245.html
46.xadmin多个model的数据渲染在统一个template中
https://www.cnblogs.com/Tommy-Yu/p/5390555.html
47.admin的空值设置方法