CRM客户关系管理系统知识点总结

一、项目需求(使用PrecessOn)

二、models.py

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)
    qq_name = models.CharField(max_length=64,blank=True,null=True)
    phone = models.CharField(max_length=64,blank=True,null=True)
    source_choices = ((0,'转介绍'),
                      (1,'QQ群'),
                      (2,'官网'),
                      (3,'百度推广'),
                      (4,'51CTO'),
                      (5,'知乎'),
                      (6,'市场推广'),
                      )

    source = models.SmallIntegerField(choices=source_choices)
    referral_from = models.CharField(verbose_name="转介绍人qq",max_length=64,blank=True,null=True)

    consult_course = models.ForeignKey("Course",verbose_name="咨询课程")
    content = models.TextField(verbose_name="咨询详情")
    tags = models.ManyToManyField("Tag",blank=True,null=True)
    status_choices = ((0,'已报名'),
                      (1,'未报名'),
                      )
    status = models.SmallIntegerField(choices=status_choices,default=1)
    consultant = models.ForeignKey("UserProfile")
    memo = models.TextField(blank=True,null=True)
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.qq

    class Meta:
        verbose_name ="客户表"
        verbose_name_plural ="客户表"

class Tag(models.Model):
    name = models.CharField(unique=True,max_length=32)

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "标签"
        verbose_name_plural = "标签"

class CustomerFollowUp(models.Model):
    '''客户跟进表'''
    customer = models.ForeignKey("Customer")
    content = models.TextField(verbose_name="跟进内容")
    consultant = models.ForeignKey("UserProfile")

    intention_choices  = ((0,'2周内报名'),
                          (1,'1个月内报名'),
                          (2,'近期无报名计划'),
                          (3,'已在其它机构报名'),
                          (4,'已报名'),
                          (5,'已拉黑'),
                          )
    intention = models.SmallIntegerField(choices=intention_choices)
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return "<%s : %s>" %(self.customer.qq,self.intention)


    class Meta:
        verbose_name = "客户跟进记录"
        verbose_name_plural = "客户跟进记录"

class Course(models.Model):
    '''课程表'''
    name = models.CharField(max_length=64,unique=True)
    price = models.PositiveSmallIntegerField()
    period = models.PositiveSmallIntegerField(verbose_name="周期(月)")
    outline = models.TextField()

    def __str__(self):
        return self.name

    class Meta:
        verbose_name = "课程表"
        verbose_name_plural = "课程表"

class Branch(models.Model):
    '''校区'''
    name = models.CharField(max_length=128,unique=True)
    addr = models.CharField(max_length=128)
    def __str__(self):
        return self.name


    class Meta:
        verbose_name = "校区"
        verbose_name_plural = "校区"

class ClassList(models.Model):
    '''班级表'''
    branch = models.ForeignKey("Branch",verbose_name="校区")
    course = models.ForeignKey("Course")
    class_type_choices = ((0,'面授(脱产)'),
                          (1,'面授(周末)'),
                          (2,'网络班')
                          )
    class_type = models.SmallIntegerField(choices=class_type_choices,verbose_name="班级类型")
    semester = models.PositiveSmallIntegerField(verbose_name="学期")
    teachers = models.ManyToManyField("UserProfile")
    start_date = models.DateField(verbose_name="开班日期")
    end_date = models.DateField(verbose_name="结业日期",blank=True,null=True)

    def __str__(self):
        return "%s %s %s" %(self.branch,self.course,self.semester)

    class Meta:
        unique_together = ('branch','course','semester')
        verbose_name_plural = "班级"
        verbose_name = "班级"

class CourseRecord(models.Model):
    '''上课记录'''
    from_class = models.ForeignKey("ClassList",verbose_name="班级")
    day_num = models.PositiveSmallIntegerField(verbose_name="第几节(天)")
    teacher = models.ForeignKey("UserProfile")
    has_homework = models.BooleanField(default=True)
    homework_title = models.CharField(max_length=128,blank=True,null=True)
    homework_content = models.TextField(blank=True,null=True)
    outline = models.TextField(verbose_name="本节课程大纲")
    date = models.DateField(auto_now_add=True)

    def __str__(self):
        return "%s %s" %(self.from_class,self.day_num)

    class Meta:
        unique_together = ("from_class", "day_num")
        verbose_name_plural = "上课记录"


class StudyRecord(models.Model):
    '''学习记录'''
    student = models.ForeignKey("Enrollment")
    course_record = models.ForeignKey("CourseRecord")
    attendance_choices = ((0,'已签到'),
                          (1,'迟到'),
                          (2,'缺勤'),
                          (3,'早退'),
                          )
    attendance = models.SmallIntegerField(choices=attendance_choices,default=0)
    score_choices = ((100,"A+"),
                     (90,"A"),
                     (85,"B+"),
                     (80,"B"),
                     (75,"B-"),
                     (70,"C+"),
                     (60,"C"),
                     (40,"C-"),
                     (-50,"D"),
                     (-100,"COPY"),
                     (0,"N/A"),
                     )
    score = models.SmallIntegerField(choices=score_choices,default=0)
    memo = models.TextField(blank=True,null=True)
    date = models.DateField(auto_now_add=True)

    def __str__(self):
        return "%s %s %s" %(self.student,self.course_record,self.score)

    class Meta:
        unique_together = ('student','course_record')
        verbose_name_plural = "学习记录"


class Enrollment(models.Model):
    '''报名表'''
    customer = models.ForeignKey("Customer")
    enrolled_class = models.ForeignKey("ClassList",verbose_name="所报班级")
    consultant = models.ForeignKey("UserProfile",verbose_name="课程顾问")
    contract_agreed = models.BooleanField(default=False,verbose_name="学员已同意合同条款")
    contract_approved = models.BooleanField(default=False,verbose_name="合同已审核")
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return "%s %s" %(self.customer,self.enrolled_class)

    class Meta:
        unique_together = ("customer","enrolled_class")
        verbose_name_plural = "报名表"

class Payment(models.Model):
    '''缴费记录'''
    customer = models.ForeignKey("Customer")
    course = models.ForeignKey("Course",verbose_name="所报课程")
    amount = models.PositiveIntegerField(verbose_name="数额",default=500)
    consultant = models.ForeignKey("UserProfile")
    date = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return "%s %s" %(self.customer,self.amount)

    class Meta:
        verbose_name_plural = "缴费记录"

class UserProfile(models.Model):
    '''账号表'''
    user = models.OneToOneField(User)
    name = models.CharField(max_length=32)
    roles = models.ManyToManyField("Role",blank=True,null=True)

    def __str__(self):
        return self.name

class Role(models.Model):
    '''角色表'''
    name = models.CharField(max_length=32,unique=True)
    menus = models.ManyToManyField("Menu",blank=True)

    def __str__(self):
        return self.name
    class Meta:
        verbose_name_plural = "角色"


class Menu(models.Model):
    '''菜单'''
    name = models.CharField(max_length=32)
    url_name = models.CharField(max_length=64)

    def __str__(self):
        return self.name
models.py

三、开发中使用的相关技术:

  DjangoBootstrapJquery等

四、项目各个功能的实现以及知识点:

1、自定义数据库表显示页面

  • 页面模板使用:Bootstarp:     http://v3.bootcss.com/examples/dashboard/
  • base.htmlindex.html
    <!DOCTYPE html>
    <!-- saved from url=(0041)http://v3.bootcss.com/examples/dashboard/ -->
    <html lang="en"><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">
        <meta name="description" content="">
        <meta name="author" content="">
        <!--link rel="icon" href="http://v3.bootcss.com/favicon.ico"-->
    
        <title>Oldboy PerfectCRM</title>
    
        <!-- Bootstrap core CSS -->
        <link href="/static/css/bootstrap.min.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>
    
    
      </head>
    {% block 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>
    <script src="/static/js/docs.min.js"></script>
    <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
    <script src="/static/js/ie10-viewport-bug-workaround.js"></script>
    
    
    </html>
    base.html
    {% extends 'base.html' %}
    
    {% block body %}
    <body>
    
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <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="#">Oldboy PefectCRM</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
    
            <li><a href="#">{{ request.user }}</a></li>
          </ul>
    
        </div>
      </div>
    </nav>
    
    <div class="container-fluid">
      <div class="row">
        <div class="col-sm-3 col-md-2 sidebar">
          <ul class="nav nav-sidebar">
            {% for  role in request.user.userprofile.roles.all %}
              {% for menu in role.menus.all %}
                <li class=""><a href="{%  url  menu.url_name %}">{{ menu.name }}</a></li>
              {% endfor %}
            {% endfor %}
    
          </ul>
    
        </div>
        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
         {% block page-content %}
          <h1 class="page-header">Dashboard</h1>
    
          <div class="row placeholders">
    
            <div class="col-xs-6 col-sm-3 placeholder">
              <img data-src="holder.js/200x200/auto/sky" class="img-responsive" alt="200x200" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDIwMCAyMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxkZWZzLz48cmVjdCB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgZmlsbD0iIzBEOEZEQiIvPjxnPjx0ZXh0IHg9Ijc1LjUiIHk9IjEwMCIgc3R5bGU9ImZpbGw6I0ZGRkZGRjtmb250LXdlaWdodDpib2xkO2ZvbnQtZmFtaWx5OkFyaWFsLCBIZWx2ZXRpY2EsIE9wZW4gU2Fucywgc2Fucy1zZXJpZiwgbW9ub3NwYWNlO2ZvbnQtc2l6ZToxMHB0O2RvbWluYW50LWJhc2VsaW5lOmNlbnRyYWwiPjIwMHgyMDA8L3RleHQ+PC9nPjwvc3ZnPg==" data-holder-rendered="true">
              <h4>Label</h4>
              <span class="text-muted">Something else</span>
            </div>
            <div class="col-xs-6 col-sm-3 placeholder">
              <img data-src="holder.js/200x200/auto/vine" class="img-responsive" alt="200x200" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDIwMCAyMDAiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxkZWZzLz48cmVjdCB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgZmlsbD0iIzM5REJBQyIvPjxnPjx0ZXh0IHg9Ijc1LjUiIHk9IjEwMCIgc3R5bGU9ImZpbGw6IzFFMjkyQztmb250LXdlaWdodDpib2xkO2ZvbnQtZmFtaWx5OkFyaWFsLCBIZWx2ZXRpY2EsIE9wZW4gU2Fucywgc2Fucy1zZXJpZiwgbW9ub3NwYWNlO2ZvbnQtc2l6ZToxMHB0O2RvbWluYW50LWJhc2VsaW5lOmNlbnRyYWwiPjIwMHgyMDA8L3RleHQ+PC9nPjwvc3ZnPg==" data-holder-rendered="true">
              <h4>Label</h4>
              <span class="text-muted">Something else</span>
            </div>
          </div>
    
          <h2 class="sub-header">Section title</h2>
    
         {% endblock %}
        </div>
      </div>
    </div>
    
    
    
    </body>
    
    {% endblock %}
    index.html
  • 显示页面:table_index.html

    {%  extends 'base.html' %}
    {% load tags %}
    
    {% block body %}
    <body>
    
    <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
      <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="#">Oldboy PefectCRM</a>
        </div>
        <div id="navbar" class="navbar-collapse collapse">
          <ul class="nav navbar-nav navbar-right">
    
            <li><a href="#">{{ request.user }}</a></li>
          </ul>
    
        </div>
      </div>
    </nav>
    
    <div class="container " style="margin: 50px; auto">
        {% block container %}
        <div class="row">
            <div class="panel panel-info">
              <div class="panel-heading">
                <h3 class="panel-title">Panel title</h3>
              </div>
              <div class="panel-body">
                {{ table_list }}
                  {% for app_name,app_tables in table_list.items %}
    
                     <table class="table table-hover">
                        <thead>
                            <tr>
                                <th>{{ app_name }}</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for table_name,admin  in app_tables.items %}
                                <tr>
                                    <td>
                                        <a href="{% url 'table_objs' app_name table_name %}">
                                           {% render_app_name admin %}
                                        </a>
                                    </td>
                                    <td>add</td>
                                    <td>change</td>
                                </tr>
                            {% endfor %}
                        </tbody>
                     </table>
                  {% endfor %}
    
              </div>
            </div>
        </div>
        {% endblock %}
    </div>
    
    
    </body>
    
    {% endblock %}
    table_index.html

  • 页面的显示
    1 from django.conf.urls import url,include
    2 from django.contrib import admin
    3 
    4 urlpatterns = [
    5     url(r'^king_admin/', include("king_admin.urls")),
    6 ]
    1 from django.conf.urls import url
    2 from king_admin import views
    3 
    4 urlpatterns = [
    5     url(r'^$', views.index,name="table_index"),
    6 ]
  • 注册要显示的表,自定义显示信息项king_admin.py

    #__author:  Administrator
    #date:  2017/1/5
    
    from crm import models
    
    
    enabled_admins = {}
    
    class BaseAdmin(object):
        list_display = []
        list_filters = []
        search_fields = []
        list_per_page = 20
        ordering = None
    
    class CustomerAdmin(BaseAdmin):
        list_display = ["id",'qq','name','source','consultant','consult_course','date','status']
        list_filters = ['source','consultant','consult_course','status','date']
        search_fields = ['qq','name',"consultant__name"]
    
        #model = models.Customer
        list_per_page = 5
        ordering = "qq"
    class CustomerFollowUpAdmin(BaseAdmin):
        list_display = ('customer','consultant','date')
    
    
    def register(model_class,admin_class=None):
        if model_class._meta.app_label not in enabled_admins:
            enabled_admins[model_class._meta.app_label] = {} #enabled_admins['crm'] = {}
        #admin_obj = admin_class()
        admin_class.model = model_class #绑定model 对象和admin 类
        enabled_admins[model_class._meta.app_label][model_class._meta.model_name] = admin_class
        #enabled_admins['crm']['customerfollowup'] = CustomerFollowUpAdmin
    
    
    register(models.Customer,CustomerAdmin)
    register(models.CustomerFollowUp,CustomerFollowUpAdmin)
    <div class="panel-body">
                {{ table_list }}
                  {% for app_name,app_tables in table_list.items %}
    
                     <table class="table table-hover">
                        <thead>
                            <tr>
                                <th>{{ app_name }}</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for table_name,admin  in app_tables.items %}
                                <tr>
                                    <td>
                                        <a href="{% url 'table_objs' app_name table_name %}">
                                           {% render_app_name admin %}
                                        </a>
                                    </td>
                                    <td>add</td>
                                    <td>change</td>
                                </tr>
                            {% endfor %}
                        </tbody>
                     </table>
                  {% endfor %}
    
              </div>
    HTML
    from django.shortcuts import render,redirect
    import importlib
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    from king_admin.utils import  table_filter,table_sort,table_search
    # Create your views here.
    from king_admin import king_admin
    from king_admin.forms import create_model_form
    
    def index(request):
        #print(king_admin.enabled_admins['crm']['customerfollowup'].model )
        return render(request, "king_admin/table_index.html",{'table_list':king_admin.enabled_admins})
    
    
    def display_table_objs(request,app_name,table_name):
    
        print("-->",app_name,table_name)
        #models_module = importlib.import_module('%s.models'%(app_name))
        #model_obj = getattr(models_module,table_name)
        admin_class = king_admin.enabled_admins[app_name][table_name]
        #admin_class = king_admin.enabled_admins[crm][userprofile]
    
        #object_list = admin_class.model.objects.all()
        object_list,filter_condtions = table_filter(request,admin_class) #过滤后的结果
    
        object_list = table_search(request,admin_class,object_list)
    
    
        object_list,orderby_key = table_sort(request, admin_class, object_list) #排序后的结果
        print("orderby key ", orderby_key)
        paginator = Paginator(object_list, admin_class.list_per_page) # Show 25 contacts per page
    
        page = request.GET.get('page')
        try:
            query_sets = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            query_sets = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            query_sets = paginator.page(paginator.num_pages)
    
        return render(request,"king_admin/table_objs.html",{"admin_class":admin_class,
                                                            "query_sets":query_sets,
                                                            "filter_condtions":filter_condtions,
                                                            "orderby_key":orderby_key,
                                                            "previous_orderby": request.GET.get("o",''),
                                                            "search_text":request.GET.get('_q','')})
    
    def table_obj_add(request,app_name,table_name):
        admin_class = king_admin.enabled_admins[app_name][table_name]
        model_form_class = create_model_form(request,admin_class)
    
        if request.method == "POST":
            form_obj = model_form_class(request.POST)  #
            if form_obj.is_valid():
                form_obj.save()
                return  redirect(request.path.replace("/add/","/"))
        else:
            form_obj = model_form_class()
    
        return render(request, "king_admin/table_obj_add.html", {"form_obj": form_obj})
    
    def table_obj_change(request,app_name,table_name,obj_id):
    
        admin_class = king_admin.enabled_admins[app_name][table_name]
        model_form_class = create_model_form(request,admin_class)
    
        obj = admin_class.model.objects.get(id=obj_id)
        if request.method == "POST":
            form_obj = model_form_class(request.POST,instance=obj) #更新
            if form_obj.is_valid():
                form_obj.save()
        else:
    
            form_obj = model_form_class(instance=obj)
    
        return render(request,"king_admin/table_obj_change.html",{"form_obj":form_obj})
    views.py

    注解:

    enabled_admins :register(model_class:表名,admin_class=None:表相关的类)  

         model_class._meta.app_label:相当于models.Customer._meta.app_label  结果为:app名:'crm'

      model_class._meta.model_name:相当于models.Customer._meta.model_name 结果:'customer'

         models.Customer._meta.verbose_name获取表的中文名

         admin_class.model = model_class相当于models.Customer

    enabled_admins[model_class._meta.app_label][model_class._meta.model_name] = admin_class  实例化类 (CustomerAdmin) 

    table_list:   table_list = king_admin.enabled_admins  当前已经注册的表, enabled_admins 中存的app、表名 

    页面跳转的实现:
    <a href="{% url 'table_objs' app_name table_name %}">
    url(r'^(w+)/(w+)/$', views.display_table_objs,name="table_objs"),
    相当于:def table_objs((w+),(w+))的两个参数为app_name table_name

    表详细信息显示页面:
    
    
    {%  extends 'king_admin/table_index.html' %}
    {% load tags %}
    
    
    
    
    {% block container %}
        {{ admin_class.list_display }}
        <div class="panel panel-info">
              <div class="panel-heading">
                <h3 class="panel-title">{% get_model_name admin_class %}
                    <a href="{{ request.path }}add/" class="pull-right">Add</a>
                </h3>
    
              </div>
              <div class="panel-body">
                   <div class="row">
                    <form class="" method="get">
                      {% for filter_field in admin_class.list_filters %}
                        <div class="col-lg-2">
                        <span>{{ filter_field }}</span>
                        {% render_filter_ele filter_field admin_class filter_condtions %}
                        </div>
    
                      {% endfor %}
    
                        <button type="SUBMIT" class="btn btn-success">检索</button>
    
                     <hr>
                      <div class="row">
                          <div class="col-lg-2" >
                            <input type="search" name="_q" class="form-control" style="margin-left:15px" value="{{ search_text }}" placeholder="search by {% for search_field in admin_class.search_fields %}{{ search_field }},{% endfor %} ">
                          </div>
                          <div class="col-lg-2" >
                            <button type="SUBMIT" class="btn btn-success">search</button>
                          </div>
                      </div>
                    </form>
    
                   </div>
    
                  <table class="table table-hover">
                      <thead>
                        <tr>
                            {% for column in admin_class.list_display %}
                                {% build_table_header_column column orderby_key filter_condtions %}
                            {% endfor %}
                        </tr>
                      </thead>
                      <tfoot>
                        <tr>
                            <td>总计{{ query_sets.paginator.count }}条</td></tr>
                      </tfoot>
                      <tbody>
    {#                    {% get_query_sets  admin_class as query_sets %}#}
                        {% for obj in query_sets %}
                        <tr>
                            {% build_table_row request obj admin_class %}
                        </tr>
                        {% endfor %}
                      </tbody>
    
                  </table>
    
    
    
              <nav>
                  <ul class="pagination">
                      {% if query_sets.has_previous %}
                            <li class=""><a href="?page={{ query_sets.previous_page_number }}">上页</a></li>
                      {% endif %}
    {#                   <li class="active"><a>{{ query_sets.number }}</a></li>#}
    
    {#                  {% for loop_counter in query_sets.paginator.page_range %}#}
    {#                        {% render_page_ele  loop_counter query_sets filter_condtions%}#}
    {#                  {% endfor %}#}
    
                      {% build_paginators query_sets   filter_condtions  previous_orderby search_text%}
    
                      {% if query_sets.has_next %}
                            <li class=""><a href="?page={{ query_sets.next_page_number }}">下页</a></li>
                      {% endif %}
    
    
    {#                <li class="disabled"><a href="#">&laquo;</a></li>#}
    {#                <li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>#}
    {#                #}
                  </ul>
              </nav>
    
    
    
              </div>
        </div>
    {% endblock %}
    table_objs.html
    
    
    from django.shortcuts import render,redirect
    import importlib
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    from king_admin.utils import  table_filter,table_sort,table_search
    # Create your views here.
    from king_admin import king_admin
    from king_admin.forms import create_model_form
    
    def index(request):
        #print(king_admin.enabled_admins['crm']['customerfollowup'].model )
    
        return render(request, "king_admin/table_index.html",{'table_list':king_admin.enabled_admins})
    
    
    def display_table_objs(request,app_name,table_name):
    
        print("-->",app_name,table_name)
        #models_module = importlib.import_module('%s.models'%(app_name))
        #model_obj = getattr(models_module,table_name)
        admin_class = king_admin.enabled_admins[app_name][table_name]
        #admin_class = king_admin.enabled_admins[crm][userprofile]
    
        #object_list = admin_class.model.objects.all()
        object_list,filter_condtions = table_filter(request,admin_class) #过滤后的结果
    
        object_list = table_search(request,admin_class,object_list)
    
    
        object_list,orderby_key = table_sort(request, admin_class, object_list) #排序后的结果
        print("orderby key ", orderby_key)
        paginator = Paginator(object_list, admin_class.list_per_page) # Show 25 contacts per page
    
        page = request.GET.get('page')
        try:
            query_sets = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            query_sets = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            query_sets = paginator.page(paginator.num_pages)
    
        return render(request,"king_admin/table_objs.html",{"admin_class":admin_class,
                                                            "query_sets":query_sets,
                                                            "filter_condtions":filter_condtions,
                                                            "orderby_key":orderby_key,
                                                            "previous_orderby": request.GET.get("o",''),
                                                            "search_text":request.GET.get('_q','')})
    
    def table_obj_add(request,app_name,table_name):
        admin_class = king_admin.enabled_admins[app_name][table_name]
        model_form_class = create_model_form(request,admin_class)
    
        if request.method == "POST":
            form_obj = model_form_class(request.POST)  #
            if form_obj.is_valid():
                form_obj.save()
                return  redirect(request.path.replace("/add/","/"))
        else:
            form_obj = model_form_class()
    
        return render(request, "king_admin/table_obj_add.html", {"form_obj": form_obj})
    
    def table_obj_change(request,app_name,table_name,obj_id):
    
        admin_class = king_admin.enabled_admins[app_name][table_name]
        model_form_class = create_model_form(request,admin_class)
    
        obj = admin_class.model.objects.get(id=obj_id)
        if request.method == "POST":
            form_obj = model_form_class(request.POST,instance=obj) #更新
            if form_obj.is_valid():
                form_obj.save()
        else:
    
            form_obj = model_form_class(instance=obj)
    
        return render(request,"king_admin/table_obj_change.html",{"form_obj":form_obj})
    views
    #__author:  Administrator
    #date:  2017/1/5
    
    from django import template
    from django.utils.safestring import mark_safe
    from django.utils.timezone import datetime,timedelta
    register = template.Library()
    
    @register.simple_tag
    def render_app_name(admin_class):
        return admin_class.model._meta.verbose_name
    
    @register.simple_tag
    def get_query_sets(admin_class):
        return admin_class.model.objects.all()
    
    @register.simple_tag
    def build_table_row(request, obj,admin_class):
        row_ele = ""
        for index,column in enumerate(admin_class.list_display):
            field_obj = obj._meta.get_field(column)
            if field_obj.choices:#choices type
                column_data = getattr(obj,"get_%s_display" % column)()
            else:
                column_data = getattr(obj,column)
    
            if type(column_data).__name__ == 'datetime':
                column_data = column_data.strftime("%Y-%m-%d %H:%M:%S")
    
            if index == 0: #add a tag, 可以跳转到修改页
                column_data = "<a href='{request_path}{obj_id}/change/'>{data}</a>".format(request_path=request.path,
                                                                                            obj_id=obj.id,
                                                                                            data=column_data)
            row_ele += "<td>%s</td>" % column_data
    
        return mark_safe(row_ele)
    
    
    @register.simple_tag
    def  build_paginators(query_sets,filter_condtions,previous_orderby,search_text):
        '''返回整个分页元素'''
        page_btns = ''
        filters = ''
        for k,v in filter_condtions.items():
            filters += "&%s=%s" %(k,v)
    
    
        added_dot_ele = False #
        for page_num in query_sets.paginator.page_range:
            if page_num < 3 or page_num > query_sets.paginator.num_pages -2 
                    or abs(query_sets.number - page_num) <= 2: #代表最前2页或最后2页 #abs判断前后1页
                ele_class = ""
                if query_sets.number == page_num:
                    added_dot_ele = False
                    ele_class = "active"
                page_btns += '''<li class="%s"><a href="?page=%s%s&o=%s&_q=%s">%s</a></li>''' % (
                ele_class, page_num, filters,previous_orderby, search_text,page_num)
            # elif abs(query_sets.number - page_num) <= 1: #判断前后1页
            #     ele_class = ""
            #     if query_sets.number == page_num:
            #         added_dot_ele = False
            #         ele_class = "active"
            #     page_btns += '''<li class="%s"><a href="?page=%s%s">%s</a></li>''' % (
            #     ele_class, page_num, filters, page_num)
            else: #显示...
                if added_dot_ele == False: #现在还没加...
                    page_btns += '<li><a>...</a></li>'
                    added_dot_ele = True
    
    
        return mark_safe(page_btns)
    
    @register.simple_tag
    def render_page_ele(loop_counter,query_sets,filter_condtions):
        filters = ''
        for k,v in filter_condtions.items():
            filters += "&%s=%s" %(k,v)
    
        if loop_counter <3 or loop_counter > query_sets.paginator.num_pages -2 : #代表这是前2页 or 最后2页
            ele_class = ""
            if query_sets.number == loop_counter:
                ele_class = "active"
            ele = '''<li class="%s"><a href="?page=%s%s">%s</a></li>''' %(ele_class,loop_counter,filters,loop_counter)
    
            return mark_safe(ele)
    
        if abs(query_sets.number - loop_counter) <= 1:
            ele_class = ""
            if query_sets.number == loop_counter:
                ele_class = "active"
            ele = '''<li class="%s"><a href="?page=%s%s">%s</a></li>''' %(ele_class,loop_counter,filters,loop_counter)
    
            return mark_safe(ele)
        else:
            return '...'
        return ''
    
    
    @register.simple_tag
    def render_filter_ele(filter_field,admin_class,filter_condtions):
        #select_ele = '''<select class="form-control" name='%s' ><option value=''>----</option>''' %filter_field
        select_ele = '''<select class="form-control" name='{filter_field}' ><option value=''>----</option>'''
        field_obj = admin_class.model._meta.get_field(filter_field)
        if field_obj.choices:
            selected = ''
            for choice_item in field_obj.choices:
                print("choice",choice_item,filter_condtions.get(filter_field),type(filter_condtions.get(filter_field)))
                if filter_condtions.get(filter_field) == str(choice_item[0]):
                    selected ="selected"
    
                select_ele += '''<option value='%s' %s>%s</option>''' %(choice_item[0],selected,choice_item[1])
                selected =''
    
        if type(field_obj).__name__ == "ForeignKey":
            selected = ''
            for choice_item in field_obj.get_choices()[1:]:
                if filter_condtions.get(filter_field) == str(choice_item[0]):
                    selected = "selected"
                select_ele += '''<option value='%s' %s>%s</option>''' %(choice_item[0],selected,choice_item[1])
                selected = ''
        if type(field_obj).__name__ in ['DateTimeField','DateField']:
            date_els = []
            today_ele = datetime.now().date()
            date_els.append(['今天', datetime.now().date()])
            date_els.append(["昨天",today_ele - timedelta(days=1)])
            date_els.append(["近7天",today_ele - timedelta(days=7)])
            date_els.append(["本月",today_ele.replace(day=1)])
            date_els.append(["近30天",today_ele - timedelta(days=30)])
            date_els.append(["近90天",today_ele - timedelta(days=90)])
            date_els.append(["近180天",today_ele - timedelta(days=180)])
            date_els.append(["本年",today_ele.replace(month=1,day=1)])
            date_els.append(["近一年",today_ele  - timedelta(days=365)])
    
            selected = ''
            for item in date_els:
                select_ele += '''<option value='%s' %s>%s</option>''' %(item[1],selected,item[0])
    
    
            filter_field_name = "%s__gte" % filter_field
    
        else:
            filter_field_name = filter_field
        select_ele += "</select>"
        select_ele = select_ele.format(filter_field=filter_field_name)
    
        return mark_safe(select_ele)
    
    @register.simple_tag
    def  build_table_header_column(column,orderby_key,filter_condtions):
        filters = ''
        for k,v in filter_condtions.items():
            filters += "&%s=%s" %(k,v)
    
        ele = '''<th><a href="?{filters}&o={orderby_key}">{column}</a>
        {sort_icon}
        </th>'''
        if orderby_key:
            if orderby_key.startswith("-"):
                sort_icon = '''<span class="glyphicon glyphicon-chevron-up"></span>'''
            else:
                sort_icon = '''<span class="glyphicon glyphicon-chevron-down"></span>'''
    
            if orderby_key.strip("-") == column: #排序的就是这个字段
                orderby_key =orderby_key
            else:
                orderby_key = column
                sort_icon = ''
    
        else:  #没有排序
            orderby_key = column
            sort_icon = ''
    
        ele = ele.format(orderby_key=orderby_key, column=column,sort_icon=sort_icon,filters=filters)
        return mark_safe(ele )
    
    
    @register.simple_tag
    def get_model_name(admin_class):
    
        return admin_class.model._meta.verbose_name
    tags.py
    #__author:  Administrator
    #date:  2017/1/5
    from django.db.models import Q
    
    def table_filter(request,admin_class):
        '''进行条件过滤并返回过滤后的数据'''
        filter_conditions = {}
        keywords = ['page','o','_q']
        for k,v in request.GET.items():
            if k in keywords:#保留的分页关键字 and 排序关键字
                continue
            if v:
                filter_conditions[k] =v
        print("filter coditions",filter_conditions)
    
        return admin_class.model.objects.filter(**filter_conditions).
                   order_by("-%s" % admin_class.ordering if admin_class.ordering else  "-id"),
                   filter_conditions
    
    def table_sort(request,admin_class,objs):
        orderby_key = request.GET.get("o")
        if orderby_key:
            res = objs.order_by(orderby_key)
            if orderby_key.startswith("-"):
                orderby_key = orderby_key.strip("-")
            else:
                orderby_key = "-%s"%orderby_key
        else:
            res = objs
        return res,orderby_key
    
    def table_search(request,admin_class,object_list):
        search_key = request.GET.get("_q","")
        q_obj = Q()
        q_obj.connector = "OR"
        for column in admin_class.search_fields:
            q_obj.children.append(("%s__contains"%column, search_key))
    
        res = object_list.filter(q_obj)
        return res
    utils.py

     注解:admin_class = king_admin.enabled_admins[app_name][table_name] 相当于:admin_class = {'crm':{'Customer':" ",'CustomerFollow':" "]}

    request.GET:获取网址红色的部分:http://127.0.0.1:8000/king_admin/crm/customer/?source=0&consultant=1&consult_course=1&status=0&date__gte=&_q=
    以字典的形式展示:{'date__gte': [''], 'consult_course': ['1'], 'status': ['0'], 'source': ['0'], 'consultant': ['1'], '_q': ['']}>
    filter coditions {'source': '0', 'status': '0', 'consult_course': '1', 'consultant': '1'}


    admin_class.model.objects.filter(**filter_conditions).order_by("-%s" % admin_class.ordering if admin_class.ordering else "-id"),
    order_by:以" "分组   (**filter_conditions):查找条件字典格式       

    filter_conditions:过滤后的数据




    
    
原文地址:https://www.cnblogs.com/shiluoliming/p/6735969.html