zoukankan      html  css  js  c++  java
  • 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  
    View Code

    24-外键下拉框添加过滤

    admin.py中发现将site字段添加到autocomplete_fields(autocomplete_fields作用是下拉选项会多出一个搜索框,方便搜索选择)之后,会自动进行过滤,满足上述场景要求。如果不使用autocomplete_fields,可以通过重写formfield_for_foreignkey方法去做筛选。如下:
    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
    xadmin/views/dashboard.py部分源码

     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>"
                             "&nbsp;&nbsp;&nbsp;<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)
    adminx.py

    增加上述方法后,还需要改变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的空值设置方法

  • 相关阅读:
    汇编-MOV指令
    mfc 线程的优先级
    golang图片裁剪和缩略图生成
    libnsq编译、使用记录
    c日志宏
    golang 六宫格、九宫格头像生成
    使用httputil中ReverseProxy反向代理遇到的坑
    Nginx反向代理与Backend直接配置长连接
    openssl:AES CBC PKCS5 加解密 (C/GOLANG)
    纯C:AES256
  • 原文地址:https://www.cnblogs.com/pgxpython/p/10217888.html
Copyright © 2011-2022 走看看