• 【Django】:重构Admin


    自定义KingAdmin

      通过admin样式自己做KingAdmin

    提前需知道的model操作

    # 获取app名
    >>> models.Customer._meta.app_label
    'repository'
    
    # 获取数据表名
    >>> models.Customer._meta.verbose_name     # verbose_name
    'customer'
    >>> models.Customer._meta.verbose_name_plural
    '客户表'  
    >>> models.Customer._meta.model_name      #表名小写
    'customer'    
    
    # 获取数据表字段、是否为choices类型
    >>> models.Customer._meta.get_field('status')
    <django.db.models.fields.SmallIntegerField: status>    #字段
    >>> models.Customer._meta.get_field('status').choices   #choices字段
    ((0, '已报名'), (1, '未报名'), (2, '已退学'), (3, '其他'))      
    >>> models.Customer._meta.get_field('id').choices     # 普通字段
    []
    >>> models.Customer._meta.get_field('consultant').choices  #外键字段
    []
    

    1、在Django项目中创建kingadmin

    2、app_config.py获取已注册以及存在kingadmin.py的App

    from django import conf
    
    for app in conf.settings.INSTALLED_APPS:
        try:
            __import__('%s.kingadmin'%app)
        except ImportError as e:
            print('%s has no model kingadmin'%app)
    

    3、views.py加载自定义的app_config.py文件

    from django.shortcuts import render
    
    from kingadmin import app_config  # 加载app_config
    from kingadmin.base_admin import site
    
    def app_index(request):
    
        print(id(site),site.registered_sites)
        return render(request, 'kingadmin/app_index.html',{'site':site})
    
    def table_data_list(request,app_name,model_name):
        admin_obj = site.registered_sites[app_name][model_name]
        admin_obj.querysets =  admin_obj.model.objects.all()
    
        return render(request,"kingadmin/table_data_list.html",locals())    # locals 传入局部变量
    

    4、base_admin.py定义注册的model(核心)

    class AdminRegisterException(Exception):
        def __init__(self,msg):
            self.message = msg
    
    
    class BaseAdmin(object):
        list_display = ()
        list_filter = ()
        search_fields = ()
        list_editable = ()
    
    
    class Adminsite(object):
        def __init__(self):
            self.registered_sites = {}
    
        def register(self,model,admin_class=None):
            '''
            :param model: <class 'crm.models.Course'>
            :param admin_class:
            :return:
            '''
            app_name = model._meta.app_label       # python manage.py shell
            model_name = model._meta.model_name     # dir(<class 'crm.models.Course'>) 查看具有的方法
            if not admin_class:
                admin_class = BaseAdmin
    
            if app_name not in self.registered_sites:
                self.registered_sites[app_name]={}
    
            if model_name in self.registered_sites[app_name]:
                raise AdminRegisterException("app [%s] model [%s] has already registered!" % (app_name, model_name))
    
            # admin_obj = admin_class()
            admin_obj = admin_class()
            admin_obj.model = model
            self.registered_sites[app_name][model_name] = admin_obj
    
    site = Adminsite()
    
    # site = {
    #     'crm':{
    #         'customers':CustomerAdmin,
    #         'customerfollowup':CustomerFollowUPAdmin,
    #     }
    # }
    

     

    5、crm目录下创建kingadmin.py进行models注册

    from kingadmin.base_admin import site,BaseAdmin
    from crm import  models
    
    class CustomerAdmin(BaseAdmin):
        list_display = ('id','name','qq','consultant','source','consult_content','status','data')
        list_filter = ('source','status','consultant')
        search_fields = ('qq','name')
        list_editable = ('status',)
    
    site.register(models.Customer,CustomerAdmin)
    site.register(models.FollowUpRecord)
    site.register(models.Enrollment)
    from django.db import models
    from django.contrib.auth.models import  User
    # Create your models here.
    
    class Customer(models.Model):
        '''潜在客户信息'''
        name = models.CharField(max_length=32,blank=True,null=True)
        qq = models.CharField(max_length=64,unique=True)
        wechat = models.CharField(max_length=64,blank=True,null=True)
        age = models.PositiveIntegerField(blank=True,null=True)
        gender = models.PositiveIntegerField(choices=((0,'Female'),(1,'Male')),blank=True,null=True)
        phone = models.PositiveIntegerField(blank=True,null=True)  #正整数
        source_choices = (
            (0,'Baidu商桥'),
            (1,'51CTO'),
            (2,'QQ群'),
            (3,'知乎'),
            (4,'SOGO'),
            (5,'转介绍'),
            (6,'其他'),
        )
        source = models.SmallIntegerField(choices=source_choices) # get_source_display 显示具体内容
        referral_from = models.ForeignKey('Customer',related_name='my_referrals',blank=True,null=True) # 自关联,字段可写slef,必须写related_name
        consult_courses = models.ManyToManyField(to='Course')
        status_choices = (
            (0,'已报名'),(1,'未报名'),(2,'已退学'),(3,'其他')
        )
        status = models.SmallIntegerField(choices=status_choices)
        consultant = models.ForeignKey(to="UserProfile",verbose_name='课程顾问')
        consult_content = models.TextField(max_length=1024)
        data = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            verbose_name_plural = '客户表'
    
        # def __str__(self):
        #     return self.name
    
    
    
    class Enrollment(models.Model):
        '''注册用户'''
        customer = models.ForeignKey('Customer')
        class_grade = models.ForeignKey('ClassList')
        enrollment_date = models.DateField()
    
        class Meta:
            unique_together = ('customer', 'class_grade')   #联合唯一
            verbose_name_plural = '注册用户表'
    
        # def __str__(self):
        #     return '%s'%self.customer
    
    
    class FollowUpRecord(models.Model):
        '''销售跟进记录'''
        customer = models.ForeignKey('Customer')
        content = models.TextField(max_length=1024)
        status_choices = (
            (0,'绝无报名计划'),
            (1,'一个月内报名'),
            (2,'两周内报名'),
            (3,'已报其他机构'),
        )
        status = models.SmallIntegerField(choices=status_choices)
        consultant = models.ForeignKey(to="UserProfile", verbose_name='课程顾问')
        data = models.DateTimeField(auto_now_add=True)
    
        class Meta:
            verbose_name_plural = '跟进记录表'
    
        # def __str__(self):
        #     return self.customer
    
    
    class Course(models.Model):
        '''课程Python,Go'''
        name = models.CharField(unique=True,max_length=32)
        price = models.PositiveIntegerField(default=19800)
        outline = models.TextField(max_length=1024)
    
        class Meta:
            verbose_name_plural = '课程表'
    
        def __str__(self):
            return self.name
    
    class ClassList(models.Model):
        '''班级s14,g1'''
        course = models.ForeignKey("Course")
        semester = models.PositiveIntegerField(verbose_name='学期')
        class_type_choices = ((0,'脱产'),(1,'周末'),(2,'网络'))
        branch = models.ForeignKey("Branch")
        class_type = models.PositiveIntegerField(choices=class_type_choices)
        teachers = models.ManyToManyField(to='UserProfile')
        start_date = models.DateField()
        end_date = models.DateField()
    
        class Meta:
            verbose_name_plural = '班级表'
    
        def __str__(self):
            return '%s'%self.course
    
    
    class CourseRecord(models.Model):
        '''每节课上课记录'''
        class_grade = models.ForeignKey('ClassList')
        day_num = models.PositiveIntegerField(verbose_name='节次')
        teacher = models.ForeignKey('UserProfile')
        CourseContent = models.TextField(verbose_name="课程内容", max_length=1024)
        has_homework = models.BooleanField(default=True)        #布尔类型
        homework_title = models.CharField(max_length=128, blank=True, null=True)
        homework_requirement = models.TextField(verbose_name="作业需求", max_length=1024, blank=True, null=True)
    
        class Meta:
            unique_together = ("class_grade", "day_num")
            verbose_name_plural = '课节次表'
    
        def __str__(self):
            return " daynum:%s" % (self.day_number)
    
    
    class StudyRecord(models.Model):
        '''每个学生上的每节课的成绩记录'''
        course_record = models.ForeignKey("CourseRecord")
        student = models.ForeignKey("Enrollment")
        score_choices = ((100, "A+"),
                         (90, "A"),
                         (85, "B+"),
                         (80, "B"),
                         (75, "B-"),
                         (70, "C+"),
                         (65, "C"),
                         (40, "C-"),
                         (-20, "D"),
                         (-50, "COPY"),
                         (0, "N/A"),
                         )
        score = models.SmallIntegerField(choices=score_choices)
        show_status_choices = (
            (0, "缺勤"), (1, "已签到"), (2, "迟到")
        )
        show_status = models.SmallIntegerField(choices=show_status_choices)
        grade_comment = models.TextField(max_length=1024, blank=True, null=True)
    
        class Meta:
            unique_together = ("course_record", "student")
            verbose_name_plural = '学员成绩记录表'
    
        def __str__(self):
            return "%s  daynum:%s" % (self.course_record, self.student)
    
    
    class UserProfile(models.Model):
        '''员工用户表'''
        user = models.OneToOneField(User)
        name = models.CharField(max_length=32)
    
        roles = models.ManyToManyField("Role")
    
        class Meta:
            verbose_name_plural = '用户表'
    
        def __str__(self):
            return self.name
    
    class Role(models.Model):
        """角色表"""
        name = models.CharField(unique=True,max_length=32)
        menus = models.ManyToManyField("Menu")
    
        class Meta:
            verbose_name_plural = '角色表'
    
        def __str__(self):
            return self.name
    
    
    class Branch(models.Model):
        """分校"""
        name = models.CharField(unique=True,max_length=128)
    
        class Meta:
            verbose_name_plural = '分校表'
    
        def __str__(self):
            return self.name
    
    
    class Menu(models.Model):
        """动态菜单"""
        name = models.CharField(unique=True,max_length=32)
        url_type = models.SmallIntegerField(choices=((0,'relative_name'),(1,'absolute_url')))
        url_name = models.CharField(unique=True,max_length=128)
    
        class Meta:
            verbose_name_plural = '菜单表'
    
        def __str__(self):
            return self.name
    model.py

    6、kingadmin目录下创建templates/kingadmin页面目录

    设置settings文件:

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates'),
                     os.path.join(BASE_DIR, 'kingadmin','templates'),]  #加入环境变量
            ,
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]
    <!DOCTYPE html>
    <!-- saved from url=(0041)http://v3.bootcss.com/examples/dashboard/ -->
    <html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
        <meta name="description" content="">
        <meta name="author" content="">
        <link rel="icon" href="http://v3.bootcss.com/favicon.ico">
    
        <title>Dashboard Template for Bootstrap</title>
    
        <!-- Bootstrap core CSS -->
        <link href="/static/css/bootstrap.min.css" rel="stylesheet">
    
        <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
        <link href="/static/css/e10-viewport-bug-workaround.css" rel="stylesheet">
    
        <!-- Custom styles for this template -->
        <link href="/static/css/dashboard.css" rel="stylesheet">
    
        <!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
        <!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
        <script src="/static/js/ie-emulation-modes-warning.js"></script>
    
        {% block header-recources %}{% endblock %}
    
      </head>
    
      <body>
        {% block body %}body ....{% endblock %}
    
        <!-- Bootstrap core JavaScript
        ================================================== -->
        <!-- Placed at the end of the document so the pages load faster -->
        <script src="/static/js/jquery.min.js"></script>
        <script src="/static/js/bootstrap.min.js"></script>
        <!-- Just to make our placeholder images work. Don't actually copy the next line! -->
        <script src="/static/js/holder.min.js"></script>
    
        <script>
    
            $(document).ready(function () {
    
                $(".nav-sidebar a[href='{{ request.path }}']").parent().addClass("active");
    
            });//end doc ready
    
    
        </script>
    </body></html>
    base.html
    {% extends "kingadmin/base.html" %}
    
    {% block body %}
    
        {% block nav-bar %}
        <nav class="navbar navbar-inverse navbar-fixed-top">
          <div class="container-fluid">
            <div class="navbar-header">
              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
              <a class="navbar-brand" href="http://v3.bootcss.com/examples/dashboard/#">Kinadmin</a>
            </div>
            <div id="navbar" class="navbar-collapse collapse">
              <ul class="nav navbar-nav navbar-right">
                <li><a href="http://v3.bootcss.com/examples/dashboard/#">Dashboard</a></li>
                <li><a href="http://v3.bootcss.com/examples/dashboard/#">Settings</a></li>
                <li><a href="http://v3.bootcss.com/examples/dashboard/#">Profile</a></li>
                <li class="dropdown">
                  <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{{ request.user.userprofile.name }}<span class="caret"></span></a>
                  <ul class="dropdown-menu">
                    <li><a href="/logout/">logout</a></li>
                    <li><a href="#">Another action</a></li>
                    <li><a href="#">Something else here</a></li>
    
                  </ul>
                </li>
    
    
    
    
              </ul>
              <form class="navbar-form navbar-right">
                <input type="text" class="form-control" placeholder="Search...">
              </form>
            </div>
          </div>
        </nav>
        {% endblock %}
    
    
    
        <div class="container-fluid">
          <div class="row">
             {% block side-bar %}
            <div class="col-sm-3 col-md-2 sidebar">
              <ul class="nav nav-sidebar">
                {% block side-bar-menus %}
                 {% for role in request.user.userprofile.roles.all %}
    {#            <li class="active"><a href="http://v3.bootcss.com/examples/dashboard/#">Overview <span class="sr-only">(current)</span></a></li>#}
                    <hr>
                    {% for menu in role.menus.all %}
                      <li>
                          <a href="{% if menu.url_type == 0 %}{% url menu.url_name %}{% else %} {{ menu.url_name }}{% endif %}"  >
                          {{ menu.name }}
                          </a>
                      </li>
                    {% endfor %}
                {% endfor %}
    
                {% endblock %}
               </ul>
    
            </div>
             {% endblock %}
            {% block right-container %}
            <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
              {% block right-container-content %}
              <h1 class="page-header">Dashboard</h1>
                    {{ request.user.userprofile.name }}
              <div class="row placeholders">
                <div class="col-xs-6 col-sm-3 placeholder">
                  <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                  <h4>Label</h4>
                  <span class="text-muted">Something else</span>
                </div>
                <div class="col-xs-6 col-sm-3 placeholder">
                  <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                  <h4>Label</h4>
                  <span class="text-muted">Something else</span>
                </div>
                <div class="col-xs-6 col-sm-3 placeholder">
                  <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                  <h4>Label</h4>
                  <span class="text-muted">Something else</span>
                </div>
                <div class="col-xs-6 col-sm-3 placeholder">
                  <img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
                  <h4>Label</h4>
                  <span class="text-muted">Something else</span>
                </div>
              </div>
    
              <h2 class="sub-header">Section title</h2>
              {% endblock %}
            </div>
            {% endblock  %}
          </div>
        </div>
    
    {% endblock %}
    index.html

    首页app_index.html:

    {% extends 'kingadmin/index.html' %}
    {% load kingadmin_tags %}
    
    {% block right-container-content %}
        {% for app,app_tables in site.registered_sites.items %}
        <table class="table table-hover">
          <thead>
            <tr>
                <h3>{{ app }}</h3>
            </tr>
          </thead>
          <tbody>
            {% for model_name,admin_class in app_tables.items %}
            <tr>
              <th ><a href="/kingadmin/{% get_app_name admin_class.model %}/{% get_model_name  admin_class.model %}/">{% get_model_verbose_name admin_class.model %}</a>  </th>
            </tr>
            {% endfor %}
          </tbody>
        </table>
        {% endfor %}
    {% endblock %}
    

    详情表table_data_list.html:  

    {% extends 'kingadmin/index.html' %}
    {% load kingadmin_tags %}
    
    {% block right-container-content %}
    
        <h4>{% get_model_verbose_name admin_obj.model  %}</h4>
    
        <table class="table table-hover">
          <thead>
            <tr>
                {% for column in admin_obj.list_display %}
                    <th>{{ column }}</th>
                {% endfor %}
            </tr>
          </thead>
          <tbody>
    
            {% for obj in admin_obj.querysets %}
                <tr>
                    {% build_table_row  admin_obj obj  %}
    
                </tr>
            {% endfor %}
          </tbody>
        </table>
    
    {% endblock %}
    

    7、创建templatetags目录下kingadmin_tags.py文件 自定义模板方法

    from django import template
    from django.utils.safestring import mark_safe
    
    register = template.Library()
    
    @register.simple_tag
    def get_model_verbose_name(model_obj):
    
        model_name = model_obj._meta.verbose_name_plural
    
        if not model_name:
            model_name = model_obj._meta.model_name
    
        return model_name
    
    @register.simple_tag
    def get_model_name(model_obj):
    
        return model_obj._meta.model_name
    
    @register.simple_tag
    def get_app_name(model_obj):
    
        return model_obj._meta.app_label
    
    @register.simple_tag
    def build_table_row(admin_obj,obj):
    
        row_ele = ""
    
        for column in admin_obj.list_display:
            column_obj = obj._meta.get_field(column)
            if column_obj.choices:
                get_column_data = getattr(obj,"get_%s_display" % column)
                column_data = get_column_data()
            else:
                column_data = getattr(obj, column)
    
            td_ele = '''<td>%s</td>''' % column_data
            row_ele += td_ele
    
        return mark_safe(row_ele)
    

    初步效果:  

    模仿Admin做检索

    1、修改views.py

    from django.shortcuts import render
    
    from kingadmin import app_config  # 加载app_config
    from kingadmin.base_admin import site
    
    def app_index(request):
    
        print(id(site),site.registered_sites)
        return render(request, 'kingadmin/app_index.html',{'site':site})
    
    def filter_querysets(request,model):    #过滤
        condtions = {}
        for k,v in request.GET.items():
            if v :
                condtions[k] = v
        querysets =model.objects.filter(**condtions)
    
        return querysets,condtions
    
    def table_data_list(request,app_name,model_name):   #重新改造函数,加上过滤条件
        # print(request.GET)
        admin_obj = site.registered_sites[app_name][model_name]
        model = admin_obj.model
        admin_obj.querysets,admin_obj.condtions =   filter_querysets(request,model)
    
        print(admin_obj.condtions)
        return render(request,"kingadmin/table_data_list.html",locals())    # locals 传入局部变量
    

    2、新增自定义simple_tag

    @register.simple_tag
    def get_filter_field(filter_column,admin_obj):
        field_obj = admin_obj.model._meta.get_field(filter_column)
    
        selected  = None
        condtions = admin_obj.condtions
        if filter_column in condtions:
            selected = condtions[filter_column]
    
        select_ele = """<select name= "%s">""" % filter_column
        for choice in field_obj.get_choices():
            if selected and selected == str(choice[0]):
                option_ele = """<option value="%s" selected> %s </option> """ % choice
            else:
                option_ele = """<option value="%s"> %s </option> """%choice
            select_ele +=option_ele
        select_ele += """</select>"""
    
        return mark_safe(select_ele)
    

    3、修改table_data_list.html

    {% extends 'kingadmin/index.html' %}
    {% load kingadmin_tags %}
    
    {% block right-container-content %}
    
        <h4>{% get_model_verbose_name admin_obj.model  %}</h4>
    {#    {{ admin_obj.list_filter }}#}
        {% if admin_obj.list_filter %}
            <div class="row">
                <form>
                    {% for filter_column in admin_obj.list_filter %}
                        <div class="col-lg-3">
                        {{ filter_column }}:{% get_filter_field filter_column admin_obj %}
                        </div>
                    {% endfor %}
                    <input type="submit" class="btn btn-success" value="过滤">
                </form>
            </div>
        {% endif %}
        <table class="table table-hover">
          <thead>
            <tr>
                {% for column in admin_obj.list_display %}
                    <th>{{ column }}</th>
                {% endfor %}
            </tr>
          </thead>
          <tbody>
    
            {% for obj in admin_obj.querysets %}
                <tr>
                    {% build_table_row  admin_obj obj  %}
    
                </tr>
            {% endfor %}
          </tbody>
        </table>
    
    
    {% endblock %}
    table_data_list.html

    显示效果:

    利用Django自带分页

    1、Paginantor官方源码示例-》跳转

    >>> from django.core.paginator import Paginator
    >>> objects = ['john', 'paul', 'george', 'ringo']
    >>> p = Paginator(objects, 2)
    
    >>> p.count
    4
    >>> p.num_pages
    2
    >>> type(p.page_range)  # `<type 'rangeiterator'>` in Python 2.
    <class 'range_iterator'>
    >>> p.page_range
    range(1, 3)
    
    >>> page1 = p.page(1)
    >>> page1
    <Page 1 of 2>
    >>> page1.object_list
    ['john', 'paul']
    
    >>> page2 = p.page(2)
    >>> page2.object_list
    ['george', 'ringo']
    >>> page2.has_next()
    False
    >>> page2.has_previous()
    True
    >>> page2.has_other_pages()
    True
    >>> page2.next_page_number()
    Traceback (most recent call last):
    ...
    EmptyPage: That page contains no results
    >>> page2.previous_page_number()
    1
    >>> page2.start_index() # The 1-based index of the first item on this page
    3
    >>> page2.end_index() # The 1-based index of the last item on this page
    4
    
    >>> p.page(0)
    Traceback (most recent call last):
    ...
    EmptyPage: That page number is less than 1
    >>> p.page(3)
    Traceback (most recent call last):
    ...
    EmptyPage: That page contains no results
    基本使用方法
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    from django.shortcuts import render
    
    def listing(request):
        contact_list = Contacts.objects.all()
        paginator = Paginator(contact_list, 25) # Show 25 contacts per page
    
        page = request.GET.get('page')
        try:
            contacts = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            contacts = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            contacts = paginator.page(paginator.num_pages)
    
        return render(request, 'list.html', {'contacts': contacts})
    后端处理
    {% for contact in contacts %}
        {# Each "contact" is a Contact model object. #}
        {{ contact.full_name|upper }}<br />
        ...
    {% endfor %}
    
    <div class="pagination">
        <span class="step-links">
            {% if contacts.has_previous %}
                <a href="?page={{ contacts.previous_page_number }}">previous</a>
            {% endif %}
    
            <span class="current">
                Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
            </span>
    
            {% if contacts.has_next %}
                <a href="?page={{ contacts.next_page_number }}">next</a>
            {% endif %}
        </span>
    </div>
    前端展示

    2、添加分页全局变量kingadmin.py

    class CustomerAdmin(BaseAdmin):
        list_display = ('id','name','qq','consultant','source','consult_content','status','data')
        list_filter = ('source','status','consultant')
        search_fields = ('qq','name')
        list_editable = ('status',)
        list_per_page = 2
    

     

    3、处理函数views.py

    def filter_querysets(request,model):    #过滤
        condtions = {}
        for k,v in request.GET.items():
            if v and k !='page':
                condtions[k] = v
        querysets =model.objects.filter(**condtions)
    
        return querysets,condtions
    
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    from django.shortcuts import render
    
    def listing(request,admin_obj):
    
        paginator = Paginator(admin_obj.querysets, admin_obj.list_per_page) # Show 25 contacts per page
        page = request.GET.get('page')
        try:
            contacts = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            contacts = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            contacts = paginator.page(paginator.num_pages)
    
        return contacts
    
    def table_data_list(request,app_name,model_name):   #重新改造函数,加上过滤条件
        # print(request.GET)
        admin_obj = site.registered_sites[app_name][model_name]
        model = admin_obj.model
        admin_obj.querysets,admin_obj.condtions =   filter_querysets(request,model)
        print('before',admin_obj.querysets)
        admin_obj.querysets = listing(request,admin_obj)
        print('after',admin_obj.querysets)
    
        return render(request,"kingadmin/table_data_list.html",locals())    # locals 传入局部变量
    

      

    4、kingadmin_tags.py

    @register.simple_tag()
    def generate_filter_url(admin_obj):
        url = ""
        for k,v in admin_obj.condtions.items():
            url += "&%s=%s"%(k,v)
    
        return url
    

    5、table_data_list.html

    tfoot>
            <nav aria-label="...">
              <ul class="pagination">
                <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a></li>
                  {% for page in admin_obj.querysets.paginator.page_range %}
                      {% if page ==  admin_obj.querysets.number  %}
                            <li class="active">
                      {% else %}
                            <li >
                      {% endif %}
                                <a href="?page={{ page }}{% generate_filter_url admin_obj %}">{{ page }} <span class="sr-only">(current)</span></a>
                            </li>
                  {% endfor %}
              </ul>
            </nav>
        </tfoot>
    

    显示效果:

    过滤、排序、分页组合

    1、在原views.py上新增:

    # 添加排序
    def get_orderby(request,querysets):         #排序
        orderby_fieid = request.GET.get('o')
        if orderby_fieid:
            querys_res = querysets.order_by(orderby_fieid)
        else:
            querys_res = querysets
    
        return querys_res
    
    # 过滤修改
    def filter_querysets(request,model):    #过滤
        condtions = {}
        except_list = ["page",'o']
        for k,v in request.GET.items():
            if k in except_list:continue
            if v:
                condtions[k] = v
        querysets =model.objects.filter(**condtions)
    
        return querysets,condtions
    
    # 分页添加
    def listing(request,admin_obj):
        querys_res = get_orderby(request, admin_obj.querysets)
    

      

    2、自定义simple_tag

    @register.simple_tag()
    def generate_filter_url(admin_obj,request=None):
        url = ""
        if request:
            if request.GET.get('o'):
                url += "&o=%s" % request.GET.get('o')
        for k,v in admin_obj.condtions.items():
            url += "&%s=%s"%(k,v)
    
        return url
    
    @register.simple_tag
    def get_orderby_key(request,column):
        current_order_by_key = request.GET.get('o')
        if current_order_by_key:
            if current_order_by_key == column:
               if column.startswith('-'):
                   column.strip("-")
               else:
                   column = "-%s"%column
            return column
        else:
            return column
    
    @register.simple_tag
    def display_order_by_icon(request,column):
        current_order_by_key = request.GET.get('o')
        if current_order_by_key:
            if current_order_by_key.strip('-') == column:
                if current_order_by_key.startswith('-'):
                    icons = '''<span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>'''
                else:
                    icons = '''<span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span>'''
    
                return mark_safe(icons)
    
        return ' '
    

      

    3、html前端页面

    // 过滤时添加排序
    <form>
        {% for filter_column in admin_obj.list_filter %}
            <div class="col-lg-3">
            {{ filter_column }}:{% get_filter_field filter_column admin_obj %}
            </div>
        {% endfor %}
        <input type="submit" class="btn btn-success" value="过滤">
        <input type="hidden" name="o" value="{{ request.GET.o }}"> //过滤时加上排序
    </form>
    
    // 排序时加上过滤
    {% for column in admin_obj.list_display %}
        <th>
            // 排序时加上过滤
            <a href="?o={% get_orderby_key request column %}{% generate_filter_url admin_obj %}"> {{ column }}</a>
            {% display_order_by_icon request column %}
        </th>
    {% endfor %}
    
    // 分页时加上过滤和排序
    {% for page in admin_obj.querysets.paginator.page_range %}
      {% if page ==  admin_obj.querysets.number  %}
            <li class="active">
      {% else %}
            <li >
      {% endif %}
                // 分页时加上排序和过滤
                <a href="?page={{ page }}{% generate_filter_url admin_obj request%}">{{ page }} <span class="sr-only">(current)</span></a>
            </li>
    {% endfor %}
    

    点击过滤或排序时页面恢复到第一页

    搜索

    1、views.py处理文件

    # 添加搜索函数 注意顺序
    
    def get_search(request,admin_obj):
        search_content = request.GET.get('q')
        condition = Q()
        condition.connector = 'OR'
        if search_content:
            for column in  admin_obj.search_fields:
                condition.children.append(("%s__contains"%column,search_content))
    
            querysets = admin_obj.querysets.filter(condition)
        else:
            querysets = admin_obj.querysets
        return querysets
    
    def table_data_list(request,app_name,model_name):   #重新改造函数,加上过滤条件
    
        admin_obj = site.registered_sites[app_name][model_name]
        model = admin_obj.model
    
        admin_obj.querysets,admin_obj.condtions =   filter_querysets(request,model) #加过滤条件
    
        admin_obj.querysets = get_search(request,admin_obj) # 搜索
    
        admin_obj.querysets = listing(request,admin_obj)        #分页
    
        return render(request,"kingadmin/table_data_list.html",locals())    # locals 传入局部变量
    

    2、自定义simple_tag

    @register.simple_tag()
    def generate_filter_search(request):
        search_content = request.GET.get('q')
        url = ""
        if search_content:
            url = "&q=%s"%search_content
    
        return url

     

    3、前端html页面

     过滤时的from
    <form>
        {% for filter_column in admin_obj.list_filter %}
            <div class="col-lg-3">
            {{ filter_column }}:{% get_filter_field filter_column admin_obj %}
            </div>
        {% endfor %}
        <input type="submit" class="btn btn-success" value="过滤">
    {#            //过滤时加上排序#}
        <input type="hidden" name="o" value="{{ request.GET.o }}">
        <br/>
        <input type="text" name="q" value="{{ request.GET.q }}">
    </form>
    
    排序
    {% for column in admin_obj.list_display %}
        <th>
    {#                    // 排序时加上过滤#}
            <a href="?o={% get_orderby_key request column %}{% generate_filter_search request %}{% generate_filter_url admin_obj %}"> {{ column }}</a>
            {% display_order_by_icon request column %}
        </th>
    {% endfor %}
    
    分页
    <a href="?page={{ page }}{% generate_filter_search request %}{% generate_filter_url admin_obj request%}">{{ page }} <span class="sr-only">(current)</span></a>
                          
    

    页面显示:

    数据修改

    1、kingadmin下创建forms.py

    from django import forms
    
    def CreateModelForm(admin_obj):     # 动态生成modelfrom
        class Meta:
            model = admin_obj.model
            fields = "__all__"
    
        dynamic_model_form = type("DynamicModelForm",(forms.ModelForm,),{'Meta':Meta})
    
        return dynamic_model_form
    

    2、views.py处理函数

    from kingadmin import forms
    def table_change(request,app_name,model_name,id):
        admin_obj = site.registered_sites[app_name][model_name]
        obj = admin_obj.model.objects.filter(id=id).first()
    
        model_form = forms.CreateModelForm(admin_obj)
        obj_form = model_form(instance=obj)
    
        return render(request,'kingadmin/table_change.html',locals())
    

     

    3、html文件

    {% extends "kingadmin/index.html" %}
    
    
    {% load kingadmin_tags %}
    
    {% block right-container-content %}
        {{ obj_form }}
    {% endblock %}
    table_change.html

    显示视图:

    修改完善

    1、html文件

    {% extends "kingadmin/index.html" %}
    
    
    {% load kingadmin_tags %}
    
    {% block right-container-content %}
        <div class="row" style="margin-bottom: 20px" >
            <ol class="breadcrumb">
              <li><a href="/kingadmin/">Home</a></li>
              <li><a href="/kingadmin/{% get_app_name admin_obj.model %}/">{% get_app_name admin_obj.model %}</a></li>
              <li ><a href="/kingadmin/{% get_app_name admin_obj.model %}/{% get_model_name admin_obj.model %}/">{% get_model_verbose_name admin_obj.model%} </a></li>
              <li class="active">{{ obj_form.instance }}</li>
            </ol>
    
            <h4>Change {% get_model_verbose_name admin_obj.model  %}</h4>
        </div>
    
        <form class="form-horizontal" method="post" onsubmit="return BeforeFormSubmit(this);">{% csrf_token %}
           {% for field in obj_form %}
                      <div class="form-group">
                        <label  class="col-sm-2 " style="font-weight: normal">
                            {% if field.field.required %}
                                <b>{{ field.label }}</b>
                            {% else %}
                                {{ field.label }}
                            {% endif %}
                        </label>
                           <div class="col-sm-10">
                            <span style="color: red;">{{ field.errors }}</span>
                                {{ field }}
                        </div>
                      </div>
           {% endfor %}
            <input type="submit" value="Save" class="pull-right btn btn-info" >
        </form>
    {% endblock %}
    table_data_list.html

    2、froms.py

    from django import forms
    
    def CreateModelForm(admin_obj):     # 动态生成modelfrom
        class Meta:
            model = admin_obj.model
            fields = "__all__"
    
        def __new__(cls, *args, **kwargs):
            # print("base fields",cls.base_fields)
            for field_name, field_obj in cls.base_fields.items():
                print(field_name,dir(field_obj))
                field_obj.widget.attrs['class'] = 'form-control'
                # field_obj.widget.attrs['maxlength'] = getattr(field_obj,'max_length' ) if hasattr(field_obj,'max_length') 
                #     else ""
                # if field_name in admin_obj.readonly_fields:
                #     field_obj.widget.attrs['disabled'] = True
    
            return forms.ModelForm.__new__(cls)
    
        dynamic_model_form = type("DynamicModelForm",(forms.ModelForm,),{'Meta':Meta})
        setattr(dynamic_model_form,"__new__",__new__)
        return dynamic_model_form

     

    3、views.py处理文件

    from kingadmin import forms
    def table_change(request,app_name,model_name,id):
        admin_obj = site.registered_sites[app_name][model_name]
        obj = admin_obj.model.objects.filter(id=id).first()
        model_form = forms.CreateModelForm(admin_obj)
    
        if request.method == "GET":
            obj_form = model_form(instance=obj)
        elif request.method == "POST":
            obj_form = model_form(instance=obj, data=request.POST)
            if obj_form.is_valid():
                obj_form.save()
    
        return render(request, "kingadmin/table_change.html", locals())
    

      

    表单添加

    1、html文件

    {% extends "kingadmin/index.html" %}
    
    
    {% load kingadmin_tags %}
    
    {% block right-container-content %}
        <div class="row" style="margin-bottom: 20px" >
            <ol class="breadcrumb">
              <li><a href="/kingadmin/">Home</a></li>
              <li><a href="/kingadmin/{% get_app_name admin_obj.model %}/">{% get_app_name admin_obj.model %}</a></li>
              <li ><a href="/kingadmin/{% get_app_name admin_obj.model %}/{% get_model_name admin_obj.model %}/">{% get_model_verbose_name admin_obj.model%} </a></li>
              <li class="active">Add {% get_model_name admin_obj.model %}</li>
            </ol>
    
            <h4>Change {% get_model_verbose_name admin_obj.model  %}</h4>
        </div>
    
        <form class="form-horizontal" method="post" onsubmit="return BeforeFormSubmit(this);">{% csrf_token %}
           {% for field in obj_form %}
                      <div class="form-group">
                        <label  class="col-sm-2 " style="font-weight: normal">
                            {% if field.field.required %}
                                <b>{{ field.label }}</b>
                            {% else %}
                                {{ field.label }}
                            {% endif %}
                        </label>
                           <div class="col-sm-10">
                            <span style="color: red;">{{ field.errors }}</span>
                                {{ field }}
                        </div>
                      </div>
           {% endfor %}
            <input type="submit" value="Save" class="pull-right btn btn-info" >
        </form>
    {% endblock %}
    table_add.html

    2、froms.py文件

    from django import forms
    
    def CreateModelForm(admin_obj):     # 动态生成modelfrom
        class Meta:
            model = admin_obj.model
            fields = "__all__"
    
        def __new__(cls, *args, **kwargs):
            # print("base fields",cls.base_fields)
            for field_name, field_obj in cls.base_fields.items():
                # print(field_name,dir(field_obj))
                field_obj.widget.attrs['class'] = 'form-control'
                # field_obj.widget.attrs['maxlength'] = getattr(field_obj,'max_length' ) if hasattr(field_obj,'max_length') 
                #     else ""
                if field_name in admin_obj.readonly_fields:
                    field_obj.widget.attrs['disabled'] = True
    
            return forms.ModelForm.__new__(cls)
    
        dynamic_model_form = type("DynamicModelForm",(forms.ModelForm,),{'Meta':Meta})
        setattr(dynamic_model_form,"__new__",__new__)
        return dynamic_model_form
    

    3、views.py处理文件

    def table_add(request,app_name,model_name):
        admin_obj = site.registered_sites[app_name][model_name]
        model_form = forms.CreateModelForm(admin_obj)
        if request.method == "GET":
            obj_form = model_form()
    
        if request.method == "POST":
            obj_form = model_form(data=request.POST)
            if obj_form.is_valid():
                obj_form.save()
            if not obj_form.errors:
                return redirect('/kingadmin/%s/%s'%(app_name,model_name))
    
        return render(request, "kingadmin/table_add.html", locals())
    

      

     

    增加readonly_fields字段

    1、forms.py文件修改

    from django import forms
    
    def CreateModelForm(admin_obj):     # 动态生成modelfrom
        class Meta:
            model = admin_obj.model
            fields = "__all__"
    
        def __new__(cls, *args, **kwargs):
            # print("base fields",cls.base_fields)
            for field_name, field_obj in cls.base_fields.items():
                # print(field_name,dir(field_obj))
                field_obj.widget.attrs['class'] = 'form-control'
                # field_obj.widget.attrs['maxlength'] = getattr(field_obj,'max_length' ) if hasattr(field_obj,'max_length') 
                #     else ""
                if field_name in admin_obj.readonly_fields:
                    field_obj.widget.attrs['disabled'] = True
    
            return forms.ModelForm.__new__(cls)
    
        def default_clean(self):
            # print("default clean:",self)
            for field in admin_obj.readonly_fields:
                print("readonly", field, self.instance)
                field_val_from_db = getattr(self.instance, field)
                field_val = self.cleaned_data.get(field)
                if field_val_from_db == field_val:
                    print("field not change ")
                else:  # 被篡改了
                    self.add_error(field, ' "%s" is a readonly field ,value should be "%s" ' % (field, field_val_from_db))
    
            print("cleaned data:", self.cleaned_data)
    
        dynamic_model_form = type("DynamicModelForm",(forms.ModelForm,),{'Meta':Meta})
        setattr(dynamic_model_form,"__new__",__new__)
        setattr(dynamic_model_form,"clean",default_clean)
        return dynamic_model_form
    

     

    添加action动作

    1、kingadmin.py

    class CustomerAdmin(BaseAdmin):
        list_display = ('id','name','qq','consultant','source','consult_content','status','data')
        list_filter = ('source','status','consultant')
        search_fields = ('qq','name')
        list_editable = ('status',)
        readonly_fields = ('name',)
        list_per_page = 5
        actions = ["change_status", ]
    
        def change_status(self, request, querysets):
            print("changeing status", querysets)
            querysets.update(status=1)
    
        change_status.short_description = "改变报名状态"
    
    class EnrollmentAdmin(BaseAdmin):
        list_display = ('customer','class_grade','enrollment_date')
    
    site.register(models.Customer,CustomerAdmin)
    site.register(models.FollowUpRecord)
    site.register(models.Enrollment,EnrollmentAdmin)
    

    2、views.py处理函数

    def table_data_list(request,app_name,model_name):   #重新改造函数,加上过滤条件
        admin_obj = site.registered_sites[app_name][model_name]
    
        if request.method == "POST":
    
            action = request.POST.get("action_select")
            selected_ids = request.POST.get("selected_ids")
            selected_ids = json.loads(selected_ids)
            print("action:",selected_ids,action)
            selected_objs = admin_obj.model.objects.filter(id__in=selected_ids)
    
            action_func = getattr(admin_obj,action)
            action_func(request,selected_objs)
    
        model = admin_obj.model
    
        admin_obj.querysets,admin_obj.condtions =   filter_querysets(request,model) #加过滤条件
    
        admin_obj.querysets = get_search(request,admin_obj) # 搜索
    
        admin_obj.querysets = listing(request,admin_obj)        #分页
    
        return render(request,"kingadmin/table_data_list.html",locals())    # locals 传入局部变量
    

      

    3、table_data_list.html

    {% extends 'kingadmin/index.html' %}
    {% load kingadmin_tags %}
    
    {% block right-container-content %}
         <ol class="breadcrumb">
              <li><a href="/kingadmin/">Home</a></li>
              <li><a href="/kingadmin/{% get_app_name admin_obj.model %}/">{% get_app_name admin_obj.model %}</a></li>
              <li class="active">{% get_model_verbose_name admin_obj.model%} </li>
              <li class="pull-right">
                  <a href="add/"><input type="button" class="btn btn-sm btn-success" value="+Add"></a>
              </li>
            </ol>
    
        <h4>{% get_model_verbose_name admin_obj.model  %}</h4>
    {#    {{ admin_obj.list_filter }}#}
    
        {% if admin_obj.list_filter %}
            <div class="row">
                <form>
                    {% for filter_column in admin_obj.list_filter %}
                        <div class="col-lg-3">
                        {{ filter_column }}:{% get_filter_field filter_column admin_obj %}
                        </div>
                    {% endfor %}
                    <input type="submit" class="btn btn-success" value="过滤">
                {#            //过滤时加上排序#}
                    <input type="hidden" name="o" value="{{ request.GET.o }}">
                    <br/>
                    <input type="text" name="q" value="{{ request.GET.q }}">
                </form>
    
    
            <form method="post" onsubmit="return ActionValidation(this)">{% csrf_token %}
                <select name="action_select">
    
                    {% get_admin_actions admin_obj %}
                </select>
                <input type="submit" value="执行">
            </form>
    
            </div>
        {% endif %}
    
        <table class="table table-hover">
          <thead>
            <tr>
             <th><input type="checkbox" onclick="SelectAll(this)" /></th>
                {% for column in admin_obj.list_display %}
                    <th>
                {#                    // 排序时加上过滤#}
                        <a href="?o={% get_orderby_key request column %}{% generate_filter_search request %}{% generate_filter_url admin_obj %}"> {{ column }}</a>
                        {% display_order_by_icon request column %}
                    </th>
                {% endfor %}
            </tr>
          </thead>
    
          <tbody>
    
            {% for obj in admin_obj.querysets %}
                <tr>
                    <td>
                        <input tag="obj_checkbox" type="checkbox" value="{{ obj.id }}" />
                    </td>
                    {% build_table_row  admin_obj obj  %}
                </tr>
            {% endfor %}
          </tbody>
        </table>
        <tfoot>
            <nav aria-label="...">
              <ul class="pagination">
                <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
                  {% for page in admin_obj.querysets.paginator.page_range %}
                      {% if page ==  admin_obj.querysets.number  %}
                            <li class="active">
                      {% else %}
                            <li >
                      {% endif %}
    {#                            // 分页时加上排序和过滤#}
                                <a href="?page={{ page }}{% generate_filter_search request %}{% generate_filter_url admin_obj request%}">{{ page }} <span class="sr-only">(current)</span></a>
                            </li>
                  {% endfor %}
              </ul>
            </nav>
        </tfoot>
    
        <script >
    
            function SelectAll(ele) {
                if ($(ele).prop("checked")){
                    $("input[tag='obj_checkbox']").prop("checked",true)
                }else {
                    $("input[tag='obj_checkbox']").prop("checked",false)
                }
    
            };//end SelectAll
    
            function ActionValidation(form_ele) {
                if ($("select[name='action_select']").val() == "-1"){
                    alert("must select action before submit!");
                    return false;
                }
    
                var selected_objs = [];
                $("input[tag='obj_checkbox']").each(function () {
                    if ($(this).prop("checked")){
                        selected_objs.push($(this).val());
                    }
                });//end each
    
                console.log(selected_objs)
                if ( selected_objs.length ==0){
                    alert("must select at least one object to run the action!");
                    return false;
                }
    
                var selected_objs_ele = "<input name='selected_ids' type='hidden' value=" + JSON.stringify(selected_objs) + " >" ;
                $(form_ele).append(selected_objs_ele);
    
                return true;
    
            }
    
        </script>
    {% endblock %}
    html

    4、simple_tag

    @register.simple_tag
    def get_admin_actions(admin_obj):
    
        options = "<option class='form-control' value='-1'>-------</option>"
        actions = admin_obj.default_actions + admin_obj.actions
    
        for action in actions:
            action_func = getattr(admin_obj,action)
            if hasattr(action_func,"short_description"):
                action_name = action_func.short_description
            else:
                action_name = action
            options += """<option value="{action_func_name}">{action_name}</option> """.format(action_func_name=action,
                                                                                               action_name=action_name)
    
        return mark_safe(options)
    

      

  • 相关阅读:
    搜广推04-信息检索任务&数据集&LeadBoard&评价指标
    搜广推&NLP03-顶会track记录
    搜广推02-DeepMatch 模型总结[SIGIR2019 tutorial]
    搜广推01-信息检索领域大佬总结
    计算机基础01-终端命令行、VIM、git、CICD
    【python】彼岸图网4K壁纸批量爬虫共1.48G(多线程/多进程)
    【python】不到500行代码实现flappybird小游戏
    解决pyinstaller打包程序太大的问题
    解决pipenv install报错FileNotFoundError: [Errno 2] No such file or directory: ‘d:\miniconda3\Lib\venv
    【python】如何将matplotlib的标题置于图片下方
  • 原文地址:https://www.cnblogs.com/lianzhilei/p/6628091.html
Copyright © 2020-2023  润新知