經過admin樣式本身作KingAdmincss
提早需知道的model操做html
# 獲取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 #外鍵字段 []
一、在Django項目中建立kingadmin前端
二、app_config.py獲取已註冊以及存在kingadmin.py的Apppython
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)
三、views.py加載自定義的app_config.py文件jquery
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 傳入局部變量
四、base_admin.py定義註冊的model(核心)shell
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, # } # }
五、crm目錄下建立kingadmin.py進行models註冊django
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
六、kingadmin目錄下建立templates/kingadmin頁面目錄json
設置settings文件:bootstrap
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>
{% 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 %}
首頁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 %}
七、建立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)
初步效果:
一、修改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 傳入局部變量
二、新增自定義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)
三、修改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 %}
顯示效果:
一、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>
二、添加分頁全局變量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
三、處理函數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 傳入局部變量
四、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
五、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>
顯示效果:
一、在原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)
二、自定義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 ' '
三、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 %}
點擊過濾或排序時頁面恢復到第一頁
一、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 傳入局部變量
二、自定義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
三、前端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>
頁面顯示:
一、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
二、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())
三、html文件
{% extends "kingadmin/index.html" %} {% load kingadmin_tags %} {% block right-container-content %} {{ obj_form }} {% endblock %}
顯示視圖:
一、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 %}
二、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
三、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())
一、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 %}
二、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
三、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())
一、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
一、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)
二、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 傳入局部變量
三、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">«</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 %}
四、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)