自定义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)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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
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',
],
},
},
]
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!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>
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{% 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 %}
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
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{% 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 %}
显示效果:
利用Django自带分页
1、Paginantor官方源码示例-》跳转
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
>>> 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
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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})
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{% 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文件
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{% extends "kingadmin/index.html" %} {% load kingadmin_tags %} {% block right-container-content %} {{ obj_form }} {% endblock %}
显示视图:
修改完善
1、html文件
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{% 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" οnsubmit="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 %}
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文件
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{% 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" οnsubmit="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 %}
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
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
{% 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" οnsubmit="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" οnclick="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 %}
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)