Xadmin开发后台管理系统

点我下载xadmin的demo

关注公众号“轻松学编程”了解更多。

添加小头像

https://blog.csdn.net/qq_34964399/article/details/80303544?utm_source=blogxgwz5

导航栏设置

https://www.cnblogs.com/adc8868/p/7506973.html

管理器常用显示设置

https://blog.csdn.net/weixin_33127753/article/details/80897240

添加插件

比如要做一个二级联动过滤查询数据,查找当前用户所办的套餐。

1、添加linkageFilter.py文件

在虚拟环境中找到/Lib/site-packages/xadmin/plugins(windows的在site-packages/xadmin/plugins),在该文件夹下添加一个linkDataFilter.py文件(文件命名随意),内容如下:

from xadmin.views import BaseAdminPlugin, DeleteAdminView
from xadmin.views.edit import CreateAdminView, UpdateAdminView
import xadmin# 点击增加记录时触发
class LinkageAddFilter(BaseAdminPlugin):# 默认不加载,只在需要加载的options中设置True来加载is_execute = Falsedef init_request(self,*arg,**kwargs):# return self.bool(is_execute)return self.is_executedef get_media(self, media):# 此处用来加入我们自己的js文件media = media + self.vendor("xadmin.self.select.js")return media
# 点击更新记录时触发
class LinkageUpdateFilter(BaseAdminPlugin):# 默认不加载,只在需要加载的options中设置True来加载is_execute = Falsedef init_request(self,*arg,**kwargs):# return self.bool(is_execute)return self.is_executedef get_media(self, media):# 此处用来加入我们自己的js文件media = media + self.vendor("xadmin.self.update_select.js")return media# 点击删除记录时触发
class LinkageDeleteFilter(BaseAdminPlugin):# 默认不加载,只在需要加载的options中设置True来加载is_execute = Falsedef init_request(self,*arg,**kwargs):# return self.bool(is_execute)return self.is_executedef get_media(self, media):# 此处用来加入我们自己的js文件media = media + self.vendor("xadmin.self.delete.js")return mediaxadmin.site.register_plugin(LinkageAddFilter, CreateAdminView)
xadmin.site.register_plugin(LinkageUpdateFilter, UpdateAdminView)
xadmin.site.register_plugin(LinkageDeleteFilter, DeleteAdminView)

2、在plugins文件夹下的init.py中PLUGINS = ()元组中添加linkDataFilter

3、写js文件

在虚拟环境中找到/Lib/site-packages/xadmin/static/xadmin/js,在该文件夹下条件xadmin.self.select.js、xadmin.self.update_select.js和xadmin.self.delete_select.js三个文件

其中xadmin.self.select.js内容如下:

(function($){function linkage_query(){// 获取用户办的套餐$("#div_id_package").click(function () {// 从导航栏处获取用户名var master_name = $('#top-nav').find('strong').text();master_name =  master_name.substring(4);url = "selectInfo/?master=" + master_name;
      getSecNav(url,'#id_package');});function getSecNav(url,id_type){$.ajax({type:"GET",url:url,async:true,beforeSend:function(xhr){xhr.setRequestHeader("X-CSRFToken", $.getCookie("csrftoken"))},success:function(data){$(id_type)[0].selectize.clearOptions(); //二级select清空选项keys = Object.keys(data);//将JSON转换);for (var i = 0; i < keys.length; i++) {console.log(data[i]);var item = data[keys[i]];var test = {text: item.name, value: item.value, $order: i + 1}; //遍历数据,拼凑出selectize需要的格式$(id_type)[0].selectize.addOption(test); //添加数据}},error:function(xhr){console.log(xhr);}});}}
  linkage_query();
})(jQuery)

4、urls.py和views.py处理js发起的请求

5、adminx.py配置

# 用户管理
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插件#  列聚合,可用的值:"count","min","max","avg",  "sum"aggregate_fields = {"id": "max"}   # 显示统计数据  统计id字段最大的值# 禁止页面批量删除,重写虚拟环境根目录下\Lib\site-packages\xadmin\views\edit.py中的has_delete_permission方法def has_delete_permission(self,*args,**kwargs):if args:return Truereturn False# 自动添加管理员,重写虚拟环境根目录下\Lib\site-packages\xadmin\views\edit.py中的save_models方法def save_models(self):self.new_obj.user = self.request.userflag = self.org_obj is None and 'create' or 'change'if flag == 'create':# 对密码字段进行加密self.new_obj.password = encrypt_oracle(self.new_obj.password)elif flag == 'change':if 'password' in self.change_message():self.new_obj.password = encrypt_oracle(self.new_obj.password)else:passsuper().save_models()# 设置用户只能查看自己填写的数据def queryset(self):qs = super(UserManageAdmin, self).queryset()if self.request.user.is_superuser:  # 超级用户可查看所有数据return qselse:que = qs.filter(user=self.request.user)return que

6、models.py

from django.db import models
from django.utils.safestring import mark_safe
from xadmin.plugins.auth import User# 用户管理
class UserManage(models.Model):name = models.CharField(max_length=20, blank=True, null=True, verbose_name='用户名')phone = models.CharField(max_length=11, unique=True, verbose_name='手机号')money = models.DecimalField(max_digits=20, decimal_places=2,default=0, verbose_name='余额')addtime = models.DateTimeField(auto_now_add=True, verbose_name='注册时间')user = models.ForeignKey(User, on_delete=models.CASCADE, editable=False, null=True, verbose_name='管理员')# 显示时增加一列,比如显示用户办的卡def get_UserManage_Taocan(self):text = '增加一列</br>'# mark_safe允许换行return mark_safe(text)get_UserManage_Taocan.short_description = '用户套餐'

7、xadmin后台集成’导入‘插件,导入excel文件

效果图:

1、添加插件

在虚拟环境根目录\Lib\site-packages\xadmin\plugins中添加excel.py文件,内容如下:

from xadmin.views import BaseAdminPlugin, ListAdminView
from django.template import loader
import xadminclass ListExcelImportPlugin(BaseAdminPlugin):# 重写init_requestimport_excel = Falsedef init_request(self, *args, **kwargs):return self.import_exceldef block_top_toolbar(self, context, nodes):# 这里 xadmin/excel/model_list.top_toolbar.import.html 是自己写的html文件nodes.append(loader.render_to_string("xadmin/excel/model_list.top_toolbar.import.html"))xadmin.site.register_plugin(ListExcelImportPlugin, ListAdminView)

2、注册插件
在虚拟环境根目录\Lib\site-packages\xadmin\plugins__init__.py中,

PLUGINS = (
...'excel',  # 在这个元祖中添加元素,名称与插件文件名同名
...
)


3、添加html文件

在虚拟环境根目录\Lib\site-packages\xadmin\templates\xadmin\中增加文件夹excel,在文件夹中添加model_list.top_toolbar.import.html文件,内容如下:

{% load i18n %}
<div class="btn-group export"><a class="dropdown-toggle btn btn-default btn-sm" data-toggle="dropdown" href="#"><i class="icon-share"></i> 导入数据 <span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel"><li><a data-toggle="modal" data-target="#export-modal-import-excel"><i class="icon-circle-arrow-down"></i> 导入Excel</a></li></ul><div id="export-modal-import-excel" class="modal fade"><div class="modal-dialog"><div class="modal-content"><form method="post" action="" enctype="multipart/form-data"><!--{% csrf_token %}--><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button><h4 class="modal-title">导入 Excel</h4></div><div class="modal-body"><input type="file" onchange="fileChange(this)" name="excel" id="submit_upload"></div><div class="modal-footer"><button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button><button class="btn btn-success" type="button" id="submit_upload_b"><i class="icon-share"></i> 导入</button></div></form></div><!-- /.modal-content --></div><!-- /.modal-dalog --></div><!-- /.modal --></div><script type="text/javascript">function fileChange(target) {//检测上传文件的类型var imgName = document.all.submit_upload.value;var ext, idx;if (imgName == '') {document.all.submit_upload_b.disabled = true;alert("请选择需要上传的 xls 文件!");return;} else {idx = imgName.lastIndexOf(".");if (idx != -1) {ext = imgName.substr(idx + 1).toUpperCase();ext = ext.toLowerCase();if (ext != 'xls' && ext != 'xlsx') {document.all.submit_upload_b.disabled = true;alert("只能上传 .xls 类型的文件!");return;}} else {document.all.submit_upload_b.disabled = true;alert("只能上传 .xls 类型的文件!");return;}}}$(document).ready(function () {$('#submit_upload_b').click(function () {var form_data = new FormData();var file_info = $('#submit_upload')[0].files[0];form_data.append('file', file_info);form_data.append('file_source', $('.breadcrumb li').eq(1).text().trim());var url = window.location.protocol + '//' + window.location.host + '/importkdorderno/'$.ajax({url: url,type: 'POST',data: form_data,dataType: "json",beforeSend: function (xhr) {xhr.setRequestHeader("X-CSRFToken", $.getCookie("csrftoken"))},processData: false,  // tell jquery not to process the datacontentType: false, // tell jquery not to set contentTypesuccess: function (res) {alert(res.msg);window.location.reload();},error: function (err) {}});});})
</script>


4、在views.py处理上传的excel文件

import pandas as pd
from rest_framework.views import APIViewclass ImportKDOrderNo(APIView):def post(self, request, *args, **kwargs):file = request.FILES.get('file')# read = InMemoryUploadedFile().open()data = pd.read_excel(file)  # 使用pandas处理excel文件file_source = request.POST.get('file_source', '')  # 文件来源if '订单号' and '物流单号' not in data:return Response(data={'msg': '文件格式有误,第一行第一列应该为【订单号】,第一行第二列应该为【物流单号】'})ordernos = data['订单号']logistics = data['物流单号']for i in range(len(ordernos)):print('订单号', ordernos[i], '物流单号', logistics[i])return Response(data={'msg': '上传成功'})

5、在urls.py中添加访问路由

from django.urls import path
from 你的应用名称 import viewsapp_name = '你的应用名称'urlpatterns = [# 其他路由...# 导入物流单号path('importkdorderno/', views.ImportKDOrderNo.as_view(), name='importkdorderno'),
]

8、xadmin后台用户操作表权限

虚拟环境根目录\Lib\site-packages\xadmin\views\base.py

可以找到:

在项目子应用下的adminx.py中使用

    import xadminfrom machine.models import Machineclass MachineAdmin(object):list_display = ['code', 'user']  # 显示的字段search_fields = ['code']  # 搜索的字段list_filter = ['code', 'is_delete'] # 过滤的字段ordering = ('-id',) # 按id降序排序list_editable = ['is_delete', ]  # 数据即时编辑readonly_fields = ['user']  # 只读字段list_per_page = 30  # 每页显示数据数量model_icon = 'fa fa-cog fa-spin'  # 左侧显示的小图标def has_delete_permission(self, *args, **kwargs): # 删除权限if self.request.user.is_superuser:  # 管理员才能增加return Truereturn Falsedef has_add_permission(self, *args, **kwargs):if self.request.user.is_superuser:  # 管理员才能增加return Truereturn Falsedef has_change_permission(self, *args, **kwargs):if self.request.user.is_superuser: # 管理员才能修改self.readonly_fields = [] # 设置管理员可以修改所有字段return Truereturn Falsedef queryset(self):"""当前用户只能看到自己的数据"""user = self.request.userif user.is_superuser:# 管理员可以查看所有数据return self.model._default_manager.get_queryset()# 当前用户只能查看自己的数据            return self.model.objects.filter(user=user)xadmin.site.register(MallMachine, MallMachineAdmin)

点我下载xadmin的demo

9、xadmin后台发送邮件找回密码

输入你用户绑定的邮箱

想要发送邮件,需要在settings.py中设置邮件发送器

settings.py最下面增加

    # ------------------------邮箱配置-----------------------------------------EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' #把要发送的邮件显示再控制台上,方便调试EMAIL_USE_SSL = TrueEMAIL_HOST = 'smtp.qq.com'  # 如果是 163 改成 smtp.163.comEMAIL_PORT = 465EMAIL_HOST_USER = '邮箱账号' # 帐号EMAIL_HOST_PASSWORD = '授权码'  # 密码DEFAULT_FROM_EMAIL = EMAIL_HOST_USER

由于django2与xadmin有些地方不兼容,需要修改源码:

找到虚拟环境根目录\Lib\site-packages\xadmin\plugins\passwords.py

在passwords.py文件中大概79行,修改为:

    return password_reset_confirm(request=request, uidb36=uidb36, token=token,template_name=self.password_reset_confirm_template,token_generator=self.password_reset_token_generator,set_password_form=self.password_reset_set_form,post_reset_redirect=self.get_admin_url('xadmin_password_reset_complete'),success_url=self.get_admin_url('xadmin_password_reset_complete'),current_app=self.admin_site.name, extra_context=context).dispatch(request=request,uidb64=uidb36,token=token)

如图:

10、xadmin消息提醒

xadmin 使用

self.message_user(u'错误,','error')
self.message_user(u'警告,','warning')
self.message_user(u'恭喜,','success')
self.message_user(u'信息,','info')

效果

11、xadmin外键下拉框添加过滤


class MallGoodsAdmin(object):"""商品管理"""list_display = ['id', 'show_photo', 'nickname', 'merchant', 'goods_class', 'label',]search_fields = ['nickname']list_filter = ['goods_class', 'label',]model_icon = 'fa fa-bars'list_editable = ['goods_class', ]# 重写虚拟环境根目录下\Lib\site-packages\xadmin\views\edit.py中的formfield_for_dbfield方法def formfield_for_dbfield(self, db_field, **kwargs):# 对MallGoodsClass这个表项的下拉框选择进行过滤# MallGoods中有一个goods_class商品分类外键MallGoodsClass,过滤掉外键MallGoodsClass中 # master_class为空的值if db_field.name == "goods_class":kwargs["queryset"] = MallGoodsClass.objects.filter(master_class__isnull=False)# 对assigned_recipient这个表项的下拉选择进行过滤return db_field.formfield(**dict(**kwargs))return super().formfield_for_dbfield(db_field, **kwargs)xadmin.site.register(models.MallGoods, MallGoodsAdmin)

12、xadmin即时编辑器去掉空标签


虚拟环境根目录下\Lib\site-packages\xadmin\plugins\editable.py,在大概

129行增加:

    form.fields[fields[0]].empty_label = None

13、用户增加的小组件,让其他用户可见

找到虚拟环境根目录\Lib\site-packages\xadmin\views\dashboard.py

在548行、554行

改为:

    @filter_hookdef get_widgets(self):if self.widget_customiz:portal_pos = UserSettings.objects.filter(key=self.get_portal_key())if len(portal_pos):portal_pos = portal_pos[0].valuewidgets = []if portal_pos:user_widgets = dict([(uw.id, uw) for uw in UserWidget.objects.filter(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 logginglogging.error(e, exc_info=True)widgets.append(ws)return widgetsreturn self.get_init_widget()

14 、xadmin导出插件处理,增加导出勾选数据项

常规的导出只有两个选择【导出表头】、【导出全部数据】

现在想要做的是增加一个选择,即【导出表头】、【导出全部数据】、【导出勾选数据】,如下图:

需要修改xadmin源代码,具体如下

1、加载js文件

找到虚拟环境\Lib\site-packages\xadmin\views\list.py,在607行增加’xadmin.plugin.importexport.js’,如下图所示

2、修改export.py,后端处理下载文件

找到虚拟环境\Lib\site-packages\xadmin\plugins\export.py

在84行把rows = context[‘results’]修改成如下函数

    # 新增导出所选数据# rows = context['results']  rows = []select_across = self.request.GET.get('_select_across', False) == '1'selected = self.request.GET.get('_selected_actions', '')if self.request.GET.get('selected', 'off') == 'on':if not select_across:selected_pk = selected.split(',')for i in context['results']:if str(i['object'].id) in selected_pk:rows.append(i)else:rows = context['results']else:rows = context['results']

3、 修改model_list.top_toolbar.exports.html

找到虚拟环境\Lib\site-packages\xadmin\templates\xadmin\blocks\model_list.top_toolbar.exports.html

使用以下代码覆盖原文件

    {% load i18n %}<div class="btn-group export"><a id="export-menu" class="dropdown-toggle btn btn-default btn-sm" data-toggle="dropdown" href="#"><i class="fa fa-share"></i> {% trans "Export" %} <span class="caret"></span></a><ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">{% for et in export_types %}<li><a data-toggle="modal" data-target="#export-modal-{{et.type}}"><i class="fa fa-arrow-circle-down"></i> {% trans "Export" %} {{et.name}}</a></li>{% endfor %}</ul>{% for et in export_types %}<div id="export-modal-{{et.type}}" class="modal fade"><div class="modal-dialog"><div class="modal-content"><form method="get" action=""><div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button><h4 class="modal-title">{% trans "Export" %} {{et.name}}</h4></div><div class="modal-body">{{ form_params|safe }}<input type="hidden" name="export_type" value="{{et.type}}"><!-- 增加 导出所选数据 一栏 --><input type="hidden" name="_selected_actions" value=""/><input type="hidden" name="_select_across" value=""/><label class="checkbox">{% if et.type == "xlsx" %}<input type="checkbox" name="export_xlsx_header" checked="checked" value="on">{% trans "Export with table header." %}{% endif %}{% if et.type == "xls" %}<input type="checkbox" name="export_xls_header" checked="checked" value="on">{% trans "Export with table header." %}{% endif %}{% if et.type == "csv" %}<input type="checkbox" name="export_csv_header" checked="checked" value="on">{% trans "Export with table header." %}{% endif %}{% if et.type == "xml" %}<input type="checkbox" name="export_xml_format" checked="checked" value="on">{% trans "Export with format." %}{% endif %}{% if et.type == "json" %}<input type="checkbox" name="export_json_format" checked="checked" value="on">{% trans "Export with format." %}{% endif %}</label><label class="checkbox"><input type="checkbox" name="all" value="on"> {% trans "Export all data." %}</label><!-- 增加 导出所选数据 一栏 --><label class="checkbox"><input type="checkbox" name="selected" value="on"> 导出勾选数据</label></div><div class="modal-footer"><button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button><button class="btn btn-success myexport  glyphicon glyphicon-export " type="submit"><iclass="fa fa-share"></i> {% trans "Export" %}</button></div></form></div><!-- /.modal-content --></div><!-- /.modal-dalog --></div><!-- /.modal -->{% endfor %}</div><script type="text/javascript">// 如果是订单导出,把待出货订单设置成待收货订单$(document).ready(function () {$('.myexport').click(function () {// 当把订单导出时,需要修改订单状态为待收货状态var url = window.location.protocol + '//' + window.location.host + "/exportorder/";$("input[name='_select_across']").val($("input[name='select_across']").val());if ($("input[name='selected']").is(':checked')) {var arr = [];$.each($('.action-select'), function () {if (true == $(this).prop('checked')) {arr.push($(this).val());}});if(arr.length == 0){alert('请先勾选导出数据')return false}}else{var arr = []var order_type = $('.breadcrumb li').eq(1).text().trim()$('.grid-item').each(function (index, el) {arr.push($(el).find('td').eq(1).text().trim())})}if (($('.breadcrumb > li').eq(1).text()).indexOf('订单') != -1) {// 5秒后执行setTimeout(function () {$.ajax({type: "POST",url: url,data: {'orderlist': JSON.stringify(arr), 'order_type': order_type,},beforeSend: function (xhr) {xhr.setRequestHeader("X-CSRFToken", $.getCookie("csrftoken"))},success: function (data) {window.location.reload();},error: function (xhr) {alert("出现未知错误");window.location.reload();}});}, 5000);}});})</script>

点我下载xadmin的demo

15、常见问题及解决方案

1、使用django2.1+xadmin搭建后台有时会出现如下错误:

lib/python3.5/site-packages/django/forms/boundfield.py", line 93, in as_widgetrenderer=self.form.renderer,TypeError: render() got an unexpected keyword argument 'renderer'

解决方案:
找到虚拟环境\Lib\site-packages\xadmin\views\dashboard.py ,在36行的render函数增加一个参数renderer=None:

def render(self, name, value, attrs=None, renderer=None)

2、 xadmin后台删除数据出现错误

    get_deleted_objects() takes 3 positional arguments but 5 were given

这是由于Django2.1版本和xadmin不兼容导致的

知道虚拟环境\Lib\site-packages\xadmin\plugins\actions.py

修改93行,

    deletable_objects, model_count, perms_needed, protected = get_deleted_objects(queryset, self.opts, self.user, self.admin_site, using)

改为

    deletable_objects, model_count, perms_needed, protected = get_deleted_objects(queryset, self.user, self.admin_site)

如果出现“‘User’ object has no attribute ‘request’”错误,则改为:

deletable_objects, model_count, perms_needed, protected = get_deleted_objects(queryset, self, self.admin_site)

然后在adminx.py文件中对应的模型类中允许删除权限

    class MaterialAdmin(object):"""素材库分类"""list_display = ['id', 'name', 'class_id', 'is_delete', 'addtime']def has_delete_permission(self, *args, **kwargs):return Truexadmin.site.register(Material, MaterialAdmin)

3、xadmin后台无法显示下拉框完整内容

解决方案 在根目录中找到/static/xadmin/vendor/selectize/selectize.bootstrap3.css
在331行后加入 position: static;

4、Django 更改超级用户密码

在工程文件目录下敲入:

    python manage.py shell

再在python交互界面输入:

    from django.contrib.auth.models import Useruser = User.objects.get(username = 'username')user.set_password('new_password')user.save()

5、xadmin后台加载数据慢,解决方案

list_filter: 过滤器要慎用,不要使用类似id这些数据量大的字段

    class MallUserAdmin(object):"""用户管理"""list_display = ['id', 'tp_icon', 'nickname', 'phone', 'level', 'balance', 'province', 'city', 'quxian']  # 显示字段search_fields = ['id', 'nickname', 'phone']  # 搜索list_filter = ['level', 'province', 'city', 'quxian']  # 过滤器# list_filter = ['id', 'level', 'province', 'city', 'quxian']  # 如果加id,xadmin加载回来的数据就会很慢,所以不要在过滤器上使用idlist_per_page = 30  # 默认每页数量model_icon = 'fa fa-users'  # 左侧图标ordering = ['-id']  # 排序readonly_fields = ['subscribe', 'wx_openid', 'phone']  # 只读字段is_addbalance = True   # 加载自定义的插件relfield_style = 'fk-ajax'  # 其他表如果外键到用户表就做ajax搜索查询,不一次性加载数据

6、xadmin使用富文本DjangoUeditor与时间插件产生冲突

现象:

原因:
加载富文本插件时,会覆盖bootstrap-clockpicker.js,bootstrap-datepicker.js,xadmin.widget.datetime.js这三个js文件
解决方案:
做一个时间插件,手动加载这个插件即可。
在adminx.py中添加:

from xadmin.views import BaseAdminPlugin, UpdateAdminView, CreateAdminView
from indent import models
class JkdPtGoodsAdmin(object):"""商品表"""list_display = ["shop", "ptgoods_name", 'price', 'pt_price', 'pt_size', 'pt_validhours','pt_state', 'is_sale']list_filter = ['is_sale', 'pt_size', 'start_time', 'pt_size']list_editable = ['price', 'start_time', 'end_time']show_detail_fields = ['ptgoods_name']search_fields = ['ptgoods_name']style_fields = {"content": "ueditor"}  # content字段使用富文本show_all_rel_details = Trueis_datetime = True   # 加载自定义的时间插件model_icon = 'fa fa-ellipsis-h'class DateTimeWidget(BaseAdminPlugin):"""时间插件"""# 默认不加载,只在需要加载的options中设置True来加载is_datetime = Falsedef init_request(self, *arg, **kwargs):return self.is_datetimedef get_media(self, media):# 此处用来加入我们自己的js文件media = media + self.vendor("xadmin.self.selectize.js","xadmin.self.select2.js","xadmin.self.select2_locale_zh-hans.js","xadmin.widget.select.js","xadmin.plugin.quick-form.js","xadmin.self.bootstrap-datepicker.js","xadmin.self.bootstrap-clockpicker.js","xadmin.widget.datetime.js", )return media# 注册时间插件
xadmin.site.register_plugin(DateTimeWidget, CreateAdminView)
xadmin.site.register_plugin(DateTimeWidget, UpdateAdminView)
xadmin.site.register(models.JkdPtGoods, JkdPtGoodsAdmin)


xadmin.self.selectize.js、
xadmin.self.select2.js、
xadmin.self.select2_locale_zh-hans.js、
xadmin.self.bootstrap-clockpicker.js、
xadmin.self.bootstrap-datepicker.js
放到项目目录/static/xadmin/js下,
xadmin.self.selectize.js中的内容复制项目根目录/static/xadmin/vendor/selectize/selectize.js中的,
xadmin.self.select2.js中的内容复制项目根目录/static/xadmin/vendor/select2/select2.js中的,
xadmin.self.select2_locale_zh-hans.js中的内容复制项目根目录/static/xadmin/vendor/select2/select2_locale_zh-hans.js中的,
xadmin.self.bootstrap-clockpicker.js中的内容复制项目根目录/static/xadmin/vendor/bootstrap-clockpicker/bootstrap-clockpicker.js中的,
xadmin.self.bootstrap-datepicker.js中的内容复制项目根目录/static/xadmin/vendor/bootstrap-datepicker/js/bootstrap-datepicker.js中的.

xadmin.widget.datetime.js、xadmin.widget.select.js、xadmin.widget.datetime.js已经在项目目录/static/xadmin/js下了

最后在xadmin.main.js文件的最后加上以下代码:

/*动态加载cee*/
var windowPrefix = window.__admin_media_prefix__;var linkList = [windowPrefix + "vendor/select2/select2.css",windowPrefix + "vendor/selectize/selectize.css",windowPrefix + "vendor/bootstrap-clockpicker/bootstrap-clockpicker.css",windowPrefix + "vendor/bootstrap-datepicker/css/datepicker.css",];for (var i = 0; i < linkList.length; i++) {$("<link>").attr({rel: "stylesheet",type: "text/css",href: linkList[i]}).appendTo("head");}

如图

7、xadmin后台编辑多对多字段

在models.py定义了多对多字段,想要在编辑时可以灵活使用这个字段的话,可以按以下方法设置:
modes.py

class Book(models.Model):title = models.CharField(verbose_name="书名", max_length=32)second_title = models.CharField(verbose_name="副标题", max_length=32, blank=True, null=True)author = models.CharField(verbose_name="作者", max_length=32)translator = models.CharField(verbose_name="译者", max_length=32, blank=True, null=True)intro = models.TextField(verbose_name="描述")pic = models.FileField(verbose_name="封面图片", max_length=64, upload_to='book_cover', null=True, blank=True)tags = models.ManyToManyField(Tags, verbose_name='书籍标签', blank=True)prizes = models.ManyToManyField(Prizes, verbose_name='获奖详情', blank=True)sump = models.IntegerField(verbose_name="收藏人数", default=0)rate_num = models.IntegerField(verbose_name="评分人数", default=0)num = models.IntegerField(verbose_name="浏览量", default=0)published_time = models.DateField(blank=True, null=True, verbose_name='出版时间')create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')class Meta:db_table = 'book'verbose_name = "图书"verbose_name_plural = "图书"def __str__(self):return self.title

adminx.py

# 书籍管理
class BookAdmin(object):search_fields = ['title', 'author', 'intro']  # 检索字段list_display = ['id', 'show_pic', 'title', 'second_title', 'author', 'translator', 'published_time', 'intro','tags', 'prizes', 'num', 'sump', 'rate_num']  # 要显示的字段list_filter = ['published_time', 'tags', 'prizes']  # 分组过滤的字段ordering = ('id',)  # 设置默认排序字段,负号表示降序排序list_per_page = 30  # 默认每页显示多少条记录,默认是100条model_icon = 'fa fa-book'  # 左侧小图标list_editable = ['title', 'author', 'intro', 'published_time']  # 可编辑字段style_fields = {'tags': 'm2m_transfer', 'prizes': 'm2m_transfer'}  # 控制字段的显示样式filter_horizontal = ('tags', 'prizes')  # 水平选择编辑多对多字段

重点是设置style_fields 和filter_horizontal ,效果:

8、xadmin通过展开方式显示TextField字段类型

由于TextField字段类型内容可能很长,在后台显示时很占屏幕位置,可以通过按钮来控制显示,代码如下:
models.py中定义了一个TextField字段类型:

class Prizes(models.Model):name = models.CharField(max_length=32, verbose_name="奖项")intro = models.TextField(blank=True, null=True, verbose_name='简介')class Meta:db_table = 'prizes'verbose_name = "奖项"verbose_name_plural = "奖项"def __str__(self):return self.name

这里使用xadmin作为后台管理框架,在adminx.py中代码如下:

# 奖项管理
class PrizesAdmin(object):search_fields = ['name']  # 检索字段list_display = ['id', 'name', 'show_intro']list_filter = ['name']ordering = ('id',)def show_intro(self, obj):# 显示简介if not obj.intro:return mark_safe('')if len(obj.intro) < 20:return mark_safe(obj.intro)short_id = f'{obj._meta.db_table}_short_text_{obj.id}'short_text_len = len(obj.intro) // 4short_text = obj.intro[:short_text_len] + '......'detail_id = f'{obj._meta.db_table}_detail_text_{obj.id}'detail_text = obj.introtext = """<style type="text/css">#%s,%s {padding:10px;border:1px solid green;} </style><script type="text/javascript">function openShutManager(oSourceObj,oTargetObj,shutAble,oOpenTip,oShutTip,oShortObj){var sourceObj = typeof oSourceObj == "string" ? document.getElementById(oSourceObj) : oSourceObj;var targetObj = typeof oTargetObj == "string" ? document.getElementById(oTargetObj) : oTargetObj;var shortObj = typeof oShortObj == "string" ? document.getElementById(oShortObj) : oShortObj;var openTip = oOpenTip || "";var shutTip = oShutTip || "";if(targetObj.style.display!="none"){if(shutAble) return;targetObj.style.display="none";shortObj.style.display="block";if(openTip  &&  shutTip){sourceObj.innerHTML = shutTip; }} else {targetObj.style.display="block";shortObj.style.display="none";if(openTip  &&  shutTip){sourceObj.innerHTML = openTip; }}}</script><p id="%s">%s</p><p><a href="###" οnclick="openShutManager(this,'%s',false,'点击关闭','点击展开','%s')">点击展开</a></p><p id="%s" style="display:none">%s</p>""" % (short_id, detail_id, short_id, short_text, detail_id, short_id, detail_id, detail_text)return mark_safe(text)show_intro.short_description = '描述'

注意:复制代码后需要做如下修改:

一开始显示效果:

点击展开效果:

9、xadmin后台批量操作

adminx.py

import xadmin
from django.db.models import  Sum
from xadmin.plugins.actions import BaseActionViewclass MyCountFeeAction(BaseActionView):"""用户余额统计"""action_name = "countuserfee"  #: 相当于这个 Action 的唯一标示, 尽量用比较针对性的名字description = u'统计用户总余额'  #: 描述, 出现在 Action 菜单中, 可以使用 ``%(verbose_name_plural)s`` 代替 Model 的名字.model_perm = 'view'  # 权限def do_action(self, queryset):all_balance = MallUser.objects.all().aggregate(Sum('balance'))return HttpResponse(f'用户总余额{all_balance}')
class UserAdmin(object):"""用户信息管理"""list_display = ['username', 'balance', 'status', 'addtime']search_fields = ['username', ]list_filter = ['status', 'addtime']list_per_page = 30  # 默认每页数量model_icon = 'fa fa-user'list_editable = ['status']ordering = ['-addtime']actions = [ MyCountFeeAction]  # 添加批量选择操作

10、xadmin过滤器外键显示特定值(比如只能过滤自己与超级管理员定义的数据)

首先,修改xadmin源码,修改xadmin/filters.py,在401行,做如下修改,

把self.lookup_choices = field.get_choices(include_blank=False)
改为:
# 调用自定义的方法if hasattr(model_admin, '{field}_choices'.format(field=field.name)):self.lookup_choices = getattr(model_admin, '{field}_choices'.format(field=field.name))(field, request,params, model,model_admin,field_path)else:self.lookup_choices = field.get_choices(include_blank=False)

如图:

然后,在adminx.py中定义过滤的方法:

import xadmin
from django.db.models import  Q, Sum
from xadmin.plugins.actions import BaseActionViewclass MeasurePointAdmin(object):# search_fields = ['user__name', 'user__account']  # 检索字段list_display = ['num', 'elevation', 'correct_num', 'cumulative_amount']list_filter = ['user', 'is_default', 'create_time']  # 分组过滤的字段list_editable = ['num', 'elevation', 'correct_num', 'cumulative_amount']ordering = ('id',)  # 设置默认排序字段,负号表示降序排序list_per_page = 30  # 默认每页显示多少条记录,默认是100条model_icon = 'fa fa-users'  # 左侧小图标readonly_fields = ['user', 'is_default']import_excel = Trueactions = [MyCountFeeAction]# 定义的函数名必须是  字段名_choicesdef user_choices(self, field, request, params, model, model_admin, field_path):# 超级用户不做控制if self.request.user.is_superuser:return field.get_choices(include_blank=False)# 过滤器只显示自己与超级管理员user_lst = field.related_model._default_manager.filter(Q(id=self.request.user.id) | Q(is_superuser=True))# 返回格式 [('pk','标题'),]return [(user.id, user.username) for user in user_lst]

效果:

点我下载xadmin的demo

后记

【后记】为了让大家能够轻松学编程,我创建了一个公众号【轻松学编程】,里面有让你快速学会编程的文章,当然也有一些干货提高你的编程水平,也有一些编程项目适合做一些课程设计等课题。

也可加我微信【1257309054】,拉你进群,大家一起交流学习。
如果文章对您有帮助,请我喝杯咖啡吧!

公众号

关注我,我们一起成长~~

xadmin开发后台管理系统常见问题相关推荐

  1. asp 退出登录修改cookie能进入后台_Vue3.0 - Composition API 体验版开发后台管理系统...

    手把手撸码前端,实战大公司级后台管理系统开发,正规实践了解项目开发整体流程 由0到1搭建后台管理系统,采用 Vue3.0 - Composition API 体验版开发,优先体验3.0 API 语法: ...

  2. antd权限管理_Ant Design Pro开发后台管理系统(权限)-阿里云开发者社区

    前言 权限是后台管理系统常见的需求,后台开发必须考虑设计的模块,antd-pro给我们提供了很好的关于权限的封装,我们只需要在配置菜单的时候配置上准入身份,在登录成功以后获取到登陆者身份以后更新登录人 ...

  3. c#chart背景透明_C#+Layui开发后台管理系统

    我是笑林新记,分享一下我一套C#开发的后台管理系统,希望对大家有帮助!欢迎关注微信公众号:笑林新记 后台开发语言:C# 前端框架:layui 前天用毛笔笔画制作了一个毛笔字效果的Logo,主要是给后台 ...

  4. 如何快速开发后台管理系统【未完,待补充,欢迎拍砖】

    一 后台管理系统的特点 (1)重功能,轻页面 (2)重效率,忌页面多次跳转 (3)表格多 二 如何快 1. 即用的前端组件 (1)css组件的积累 (2)js组件的积累 见 http://www.cn ...

  5. Python+django+xadmin学习与开发笔记【04】快速开发后台管理系统

    [先试试django自带的admin] 创建superuser,但报错了..发现user表里的gender长度设置小了(female是6个字符)于是update一下这个字段,参考https://blo ...

  6. xadmin与mysql数据库_django和xadmin打造后台管理系统(一)-xadmin安装及使用

    安装完django,该安装xadmin了,我们都知道django有自己的原生后台admin,但这里我们不用admin,我们用xadmin,因为xadmin的界面更加漂亮. 1.xadmin的安装 首先 ...

  7. 使用vue-admin-template基础模板开发后台管理系统必会技能

    1.必会一 :vue-cli vue-admin-template的使用建立在vue-cli(脚手架)基础上.官网 2.必会二 : vue-router 路由是个很重要的角色,可以管控登录权限,负责页 ...

  8. 使用moy快速开发后台管理系统(二)

    moy是什么? moy 是基于模型框架 kero 和 UI 框架 neoui 实现的应用框架,是前端集成解决方案,为企业级应用开发而生. github地址:https://github.com/iua ...

  9. Ant Design Pro开发后台管理系统(新增页面)

    通过实际demo演示一个管理后台的开发过程 知识点: 1.新增router,新增models 新增菜单配置 1.如上图所示,打开/src/common/menu.js可以看到菜单列表 其中 menuD ...

最新文章

  1. 30年间,软件开发行业为何Bug纷飞?
  2. java转置矩阵相乘_java实现矩阵的加-减-乘-转置运算
  3. 求三角形最大面积(DP)
  4. python3实现抓取网页资源的 N 种方法(内附200GPython学习资料)
  5. Python 基础知识(二)
  6. 输入身份证号,输出出生日期
  7. 一加10 Pro胖达白512GB至尊版发布 售价5799元
  8. Android Broadcast 和 BroadcastReceiver的权限限制
  9. android textview adapter,Android在FragmentPagerAdapter中的Fragment中设置TextView文本
  10. 全国海关分区图(含副厅)
  11. 数学建模计算机部分知识,数学建模相关论文范文资料,与数学建模与计算机关系相关毕业论文题目范文...
  12. 智能合约审计之整形溢出攻击
  13. es---elasticsearch-篇二:idea操作es,常用查询DSL
  14. python发微信提醒天气_基于Python实现定时自动给微信好友发送天气预报
  15. MySQL02--高级(BTreeB+Tree、聚簇索引非聚簇索引、性能分析(Explain)、索引、sql优化)
  16. 虚幻四蓝图实战(下车减速人物加速蓝图接口通信)
  17. NXP i.MX 8M Mini开发板(4核 ARM Cortex-A53)硬件原理图规格说明书
  18. DaVinci Resolve Studio达芬奇调色v17.0.0.39安装说明
  19. ARM外设 cortex-a8
  20. JAVA银企直连建设银行云直连模式超详细讲解

热门文章

  1. html图片怎么设置热区不大小,店铺装修技巧之图片尺寸大全!收藏必备!随时可查看!...
  2. 基于MATLAB的三种边缘检测数字图像处理(sobel、Marr-Hildreth、Canny)
  3. InsecureRequestWarning: Unverified HTTPS request is being made
  4. 360软件管家怎么下载python_python 爬虫爬取360安全卫士对某一个号码的标识
  5. 使用Easypoi实现Excel导入导出
  6. 史上最新最全的M1 Air(2020 macbook air)配置homebrew步骤
  7. 一针见血评互联网五大巨头:腾讯贪、阿里全、百度狠、小米直、奇虎360难
  8. Fortran学习13:IO 2
  9. 转一位好友的《中国软件业的断想》
  10. 金蝶钉钉对接方案介绍