Python开发【Django】:重构Admin
自定义KingAdmin
通过admin样式自己做KingAdmin
提前需知道的model操作
# 获取app名
>>> models.Customer._meta.app_label
'repository' # 获取数据表名
>>> models.Customer._meta.verbose_name # verbose_name
'customer'
>>> models.Customer._meta.verbose_name_plural
'客户表'
>>> models.Customer._meta.model_name #表名小写
'customer' # 获取数据表字段、是否为choices类型
>>> models.Customer._meta.get_field('status')
<django.db.models.fields.SmallIntegerField: status> #字段
>>> models.Customer._meta.get_field('status').choices #choices字段
((0, '已报名'), (1, '未报名'), (2, '已退学'), (3, '其他'))
>>> models.Customer._meta.get_field('id').choices # 普通字段
[]
>>> models.Customer._meta.get_field('consultant').choices #外键字段
[]
1、在Django项目中创建kingadmin
2、app_config.py获取已注册以及存在kingadmin.py的App
from django import conf for app in conf.settings.INSTALLED_APPS:
try:
__import__('%s.kingadmin'%app)
except ImportError as e:
print('%s has no model kingadmin'%app)
3、views.py加载自定义的app_config.py文件
from django.shortcuts import render from kingadmin import app_config # 加载app_config
from kingadmin.base_admin import site def app_index(request): print(id(site),site.registered_sites)
return render(request, 'kingadmin/app_index.html',{'site':site}) def table_data_list(request,app_name,model_name):
admin_obj = site.registered_sites[app_name][model_name]
admin_obj.querysets = admin_obj.model.objects.all() return render(request,"kingadmin/table_data_list.html",locals()) # locals 传入局部变量
4、base_admin.py定义注册的model(核心)
class AdminRegisterException(Exception):
def __init__(self,msg):
self.message = msg class BaseAdmin(object):
list_display = ()
list_filter = ()
search_fields = ()
list_editable = () class Adminsite(object):
def __init__(self):
self.registered_sites = {} def register(self,model,admin_class=None):
'''
:param model: <class 'crm.models.Course'>
:param admin_class:
:return:
'''
app_name = model._meta.app_label # python manage.py shell
model_name = model._meta.model_name # dir(<class 'crm.models.Course'>) 查看具有的方法
if not admin_class:
admin_class = BaseAdmin if app_name not in self.registered_sites:
self.registered_sites[app_name]={} if model_name in self.registered_sites[app_name]:
raise AdminRegisterException("app [%s] model [%s] has already registered!" % (app_name, model_name)) # admin_obj = admin_class()
admin_obj = admin_class()
admin_obj.model = model
self.registered_sites[app_name][model_name] = admin_obj site = Adminsite() # site = {
# 'crm':{
# 'customers':CustomerAdmin,
# 'customerfollowup':CustomerFollowUPAdmin,
# }
# }
5、crm目录下创建kingadmin.py进行models注册
from kingadmin.base_admin import site,BaseAdmin
from crm import models class CustomerAdmin(BaseAdmin):
list_display = ('id','name','qq','consultant','source','consult_content','status','data')
list_filter = ('source','status','consultant')
search_fields = ('qq','name')
list_editable = ('status',) site.register(models.Customer,CustomerAdmin)
site.register(models.FollowUpRecord)
site.register(models.Enrollment)
from django.db import models
from django.contrib.auth.models import User
# Create your models here. class Customer(models.Model):
'''潜在客户信息'''
name = models.CharField(max_length=32,blank=True,null=True)
qq = models.CharField(max_length=64,unique=True)
wechat = models.CharField(max_length=64,blank=True,null=True)
age = models.PositiveIntegerField(blank=True,null=True)
gender = models.PositiveIntegerField(choices=((0,'Female'),(1,'Male')),blank=True,null=True)
phone = models.PositiveIntegerField(blank=True,null=True) #正整数
source_choices = (
(0,'Baidu商桥'),
(1,'51CTO'),
(2,'QQ群'),
(3,'知乎'),
(4,'SOGO'),
(5,'转介绍'),
(6,'其他'),
)
source = models.SmallIntegerField(choices=source_choices) # get_source_display 显示具体内容
referral_from = models.ForeignKey('Customer',related_name='my_referrals',blank=True,null=True) # 自关联,字段可写slef,必须写related_name
consult_courses = models.ManyToManyField(to='Course')
status_choices = (
(0,'已报名'),(1,'未报名'),(2,'已退学'),(3,'其他')
)
status = models.SmallIntegerField(choices=status_choices)
consultant = models.ForeignKey(to="UserProfile",verbose_name='课程顾问')
consult_content = models.TextField(max_length=1024)
data = models.DateTimeField(auto_now_add=True) class Meta:
verbose_name_plural = '客户表' # def __str__(self):
# return self.name class Enrollment(models.Model):
'''注册用户'''
customer = models.ForeignKey('Customer')
class_grade = models.ForeignKey('ClassList')
enrollment_date = models.DateField() class Meta:
unique_together = ('customer', 'class_grade') #联合唯一
verbose_name_plural = '注册用户表' # def __str__(self):
# return '%s'%self.customer class FollowUpRecord(models.Model):
'''销售跟进记录'''
customer = models.ForeignKey('Customer')
content = models.TextField(max_length=1024)
status_choices = (
(0,'绝无报名计划'),
(1,'一个月内报名'),
(2,'两周内报名'),
(3,'已报其他机构'),
)
status = models.SmallIntegerField(choices=status_choices)
consultant = models.ForeignKey(to="UserProfile", verbose_name='课程顾问')
data = models.DateTimeField(auto_now_add=True) class Meta:
verbose_name_plural = '跟进记录表' # def __str__(self):
# return self.customer class Course(models.Model):
'''课程Python,Go'''
name = models.CharField(unique=True,max_length=32)
price = models.PositiveIntegerField(default=19800)
outline = models.TextField(max_length=1024) class Meta:
verbose_name_plural = '课程表' def __str__(self):
return self.name class ClassList(models.Model):
'''班级s14,g1'''
course = models.ForeignKey("Course")
semester = models.PositiveIntegerField(verbose_name='学期')
class_type_choices = ((0,'脱产'),(1,'周末'),(2,'网络'))
branch = models.ForeignKey("Branch")
class_type = models.PositiveIntegerField(choices=class_type_choices)
teachers = models.ManyToManyField(to='UserProfile')
start_date = models.DateField()
end_date = models.DateField() class Meta:
verbose_name_plural = '班级表' def __str__(self):
return '%s'%self.course class CourseRecord(models.Model):
'''每节课上课记录'''
class_grade = models.ForeignKey('ClassList')
day_num = models.PositiveIntegerField(verbose_name='节次')
teacher = models.ForeignKey('UserProfile')
CourseContent = models.TextField(verbose_name="课程内容", max_length=1024)
has_homework = models.BooleanField(default=True) #布尔类型
homework_title = models.CharField(max_length=128, blank=True, null=True)
homework_requirement = models.TextField(verbose_name="作业需求", max_length=1024, blank=True, null=True) class Meta:
unique_together = ("class_grade", "day_num")
verbose_name_plural = '课节次表' def __str__(self):
return " daynum:%s" % (self.day_number) class StudyRecord(models.Model):
'''每个学生上的每节课的成绩记录'''
course_record = models.ForeignKey("CourseRecord")
student = models.ForeignKey("Enrollment")
score_choices = ((100, "A+"),
(90, "A"),
(85, "B+"),
(80, "B"),
(75, "B-"),
(70, "C+"),
(65, "C"),
(40, "C-"),
(-20, "D"),
(-50, "COPY"),
(0, "N/A"),
)
score = models.SmallIntegerField(choices=score_choices)
show_status_choices = (
(0, "缺勤"), (1, "已签到"), (2, "迟到")
)
show_status = models.SmallIntegerField(choices=show_status_choices)
grade_comment = models.TextField(max_length=1024, blank=True, null=True) class Meta:
unique_together = ("course_record", "student")
verbose_name_plural = '学员成绩记录表' def __str__(self):
return "%s daynum:%s" % (self.course_record, self.student) class UserProfile(models.Model):
'''员工用户表'''
user = models.OneToOneField(User)
name = models.CharField(max_length=32) roles = models.ManyToManyField("Role") class Meta:
verbose_name_plural = '用户表' def __str__(self):
return self.name class Role(models.Model):
"""角色表"""
name = models.CharField(unique=True,max_length=32)
menus = models.ManyToManyField("Menu") class Meta:
verbose_name_plural = '角色表' def __str__(self):
return self.name class Branch(models.Model):
"""分校"""
name = models.CharField(unique=True,max_length=128) class Meta:
verbose_name_plural = '分校表' def __str__(self):
return self.name class Menu(models.Model):
"""动态菜单"""
name = models.CharField(unique=True,max_length=32)
url_type = models.SmallIntegerField(choices=((0,'relative_name'),(1,'absolute_url')))
url_name = models.CharField(unique=True,max_length=128) class Meta:
verbose_name_plural = '菜单表' def __str__(self):
return self.name
model.py
6、kingadmin目录下创建templates/kingadmin页面目录
设置settings文件:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates'),
os.path.join(BASE_DIR, 'kingadmin','templates'),] #加入环境变量
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
<!DOCTYPE html>
<!-- saved from url=(0041)http://v3.bootcss.com/examples/dashboard/ -->
<html lang="zh-CN"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="http://v3.bootcss.com/favicon.ico"> <title>Dashboard Template for Bootstrap</title> <!-- Bootstrap core CSS -->
<link href="/static/css/bootstrap.min.css" rel="stylesheet"> <!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
<link href="/static/css/e10-viewport-bug-workaround.css" rel="stylesheet"> <!-- Custom styles for this template -->
<link href="/static/css/dashboard.css" rel="stylesheet"> <!-- Just for debugging purposes. Don't actually copy these 2 lines! -->
<!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]-->
<script src="/static/js/ie-emulation-modes-warning.js"></script> {% block header-recources %}{% endblock %} </head> <body>
{% block body %}body ....{% endblock %} <!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="/static/js/jquery.min.js"></script>
<script src="/static/js/bootstrap.min.js"></script>
<!-- Just to make our placeholder images work. Don't actually copy the next line! -->
<script src="/static/js/holder.min.js"></script> <script> $(document).ready(function () { $(".nav-sidebar a[href='{{ request.path }}']").parent().addClass("active"); });//end doc ready </script>
</body></html>
base.html
{% extends "kingadmin/base.html" %} {% block body %} {% block nav-bar %}
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="http://v3.bootcss.com/examples/dashboard/#">Kinadmin</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<li><a href="http://v3.bootcss.com/examples/dashboard/#">Dashboard</a></li>
<li><a href="http://v3.bootcss.com/examples/dashboard/#">Settings</a></li>
<li><a href="http://v3.bootcss.com/examples/dashboard/#">Profile</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{{ request.user.userprofile.name }}<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="/logout/">logout</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li> </ul>
</li> </ul>
<form class="navbar-form navbar-right">
<input type="text" class="form-control" placeholder="Search...">
</form>
</div>
</div>
</nav>
{% endblock %} <div class="container-fluid">
<div class="row">
{% block side-bar %}
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
{% block side-bar-menus %}
{% for role in request.user.userprofile.roles.all %}
{# <li class="active"><a href="http://v3.bootcss.com/examples/dashboard/#">Overview <span class="sr-only">(current)</span></a></li>#}
<hr>
{% for menu in role.menus.all %}
<li>
<a href="{% if menu.url_type == 0 %}{% url menu.url_name %}{% else %} {{ menu.url_name }}{% endif %}" >
{{ menu.name }}
</a>
</li>
{% endfor %}
{% endfor %} {% endblock %}
</ul> </div>
{% endblock %}
{% block right-container %}
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
{% block right-container-content %}
<h1 class="page-header">Dashboard</h1>
{{ request.user.userprofile.name }}
<div class="row placeholders">
<div class="col-xs-6 col-sm-3 placeholder">
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="" height="" 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="" height="" 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="" height="" 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="" height="" class="img-responsive" alt="Generic placeholder thumbnail">
<h4>Label</h4>
<span class="text-muted">Something else</span>
</div>
</div> <h2 class="sub-header">Section title</h2>
{% endblock %}
</div>
{% endblock %}
</div>
</div> {% endblock %}
index.html
首页app_index.html:
{% extends 'kingadmin/index.html' %}
{% load kingadmin_tags %} {% block right-container-content %}
{% for app,app_tables in site.registered_sites.items %}
<table class="table table-hover">
<thead>
<tr>
<h3>{{ app }}</h3>
</tr>
</thead>
<tbody>
{% for model_name,admin_class in app_tables.items %}
<tr>
<th ><a href="/kingadmin/{% get_app_name admin_class.model %}/{% get_model_name admin_class.model %}/">{% get_model_verbose_name admin_class.model %}</a> </th>
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
{% endblock %}
详情表table_data_list.html:
{% extends 'kingadmin/index.html' %}
{% load kingadmin_tags %} {% block right-container-content %} <h4>{% get_model_verbose_name admin_obj.model %}</h4> <table class="table table-hover">
<thead>
<tr>
{% for column in admin_obj.list_display %}
<th>{{ column }}</th>
{% endfor %}
</tr>
</thead>
<tbody> {% for obj in admin_obj.querysets %}
<tr>
{% build_table_row admin_obj obj %} </tr>
{% endfor %}
</tbody>
</table> {% endblock %}
7、创建templatetags目录下kingadmin_tags.py文件 自定义模板方法
from django import template
from django.utils.safestring import mark_safe register = template.Library() @register.simple_tag
def get_model_verbose_name(model_obj): model_name = model_obj._meta.verbose_name_plural if not model_name:
model_name = model_obj._meta.model_name return model_name @register.simple_tag
def get_model_name(model_obj): return model_obj._meta.model_name @register.simple_tag
def get_app_name(model_obj): return model_obj._meta.app_label @register.simple_tag
def build_table_row(admin_obj,obj): row_ele = "" for column in admin_obj.list_display:
column_obj = obj._meta.get_field(column)
if column_obj.choices:
get_column_data = getattr(obj,"get_%s_display" % column)
column_data = get_column_data()
else:
column_data = getattr(obj, column) td_ele = '''<td>%s</td>''' % column_data
row_ele += td_ele return mark_safe(row_ele)
初步效果:
模仿Admin做检索
1、修改views.py
from django.shortcuts import render from kingadmin import app_config # 加载app_config
from kingadmin.base_admin import site def app_index(request): print(id(site),site.registered_sites)
return render(request, 'kingadmin/app_index.html',{'site':site}) def filter_querysets(request,model): #过滤
condtions = {}
for k,v in request.GET.items():
if v :
condtions[k] = v
querysets =model.objects.filter(**condtions) return querysets,condtions def table_data_list(request,app_name,model_name): #重新改造函数,加上过滤条件
# print(request.GET)
admin_obj = site.registered_sites[app_name][model_name]
model = admin_obj.model
admin_obj.querysets,admin_obj.condtions = filter_querysets(request,model) print(admin_obj.condtions)
return render(request,"kingadmin/table_data_list.html",locals()) # locals 传入局部变量
2、新增自定义simple_tag
@register.simple_tag
def get_filter_field(filter_column,admin_obj):
field_obj = admin_obj.model._meta.get_field(filter_column) selected = None
condtions = admin_obj.condtions
if filter_column in condtions:
selected = condtions[filter_column] select_ele = """<select name= "%s">""" % filter_column
for choice in field_obj.get_choices():
if selected and selected == str(choice[0]):
option_ele = """<option value="%s" selected> %s </option> """ % choice
else:
option_ele = """<option value="%s"> %s </option> """%choice
select_ele +=option_ele
select_ele += """</select>""" return mark_safe(select_ele)
3、修改table_data_list.html
{% extends 'kingadmin/index.html' %}
{% load kingadmin_tags %} {% block right-container-content %} <h4>{% get_model_verbose_name admin_obj.model %}</h4>
{# {{ admin_obj.list_filter }}#}
{% if admin_obj.list_filter %}
<div class="row">
<form>
{% for filter_column in admin_obj.list_filter %}
<div class="col-lg-3">
{{ filter_column }}:{% get_filter_field filter_column admin_obj %}
</div>
{% endfor %}
<input type="submit" class="btn btn-success" value="过滤">
</form>
</div>
{% endif %}
<table class="table table-hover">
<thead>
<tr>
{% for column in admin_obj.list_display %}
<th>{{ column }}</th>
{% endfor %}
</tr>
</thead>
<tbody> {% for obj in admin_obj.querysets %}
<tr>
{% build_table_row admin_obj obj %} </tr>
{% endfor %}
</tbody>
</table> {% endblock %}
table_data_list.html
显示效果:
利用Django自带分页
1、Paginantor官方源码示例-》跳转
>>> from django.core.paginator import Paginator
>>> objects = ['john', 'paul', 'george', 'ringo']
>>> p = Paginator(objects, 2) >>> p.count
4
>>> p.num_pages
2
>>> type(p.page_range) # `<type 'rangeiterator'>` in Python 2.
<class 'range_iterator'>
>>> p.page_range
range(1, 3) >>> page1 = p.page(1)
>>> page1
<Page 1 of 2>
>>> page1.object_list
['john', 'paul'] >>> page2 = p.page(2)
>>> page2.object_list
['george', 'ringo']
>>> page2.has_next()
False
>>> page2.has_previous()
True
>>> page2.has_other_pages()
True
>>> page2.next_page_number()
Traceback (most recent call last):
...
EmptyPage: That page contains no results
>>> page2.previous_page_number()
1
>>> page2.start_index() # The 1-based index of the first item on this page
3
>>> page2.end_index() # The 1-based index of the last item on this page
4 >>> p.page(0)
Traceback (most recent call last):
...
EmptyPage: That page number is less than 1
>>> p.page(3)
Traceback (most recent call last):
...
EmptyPage: That page contains no results
基本使用方法
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render def listing(request):
contact_list = Contacts.objects.all()
paginator = Paginator(contact_list, 25) # Show 25 contacts per page page = request.GET.get('page')
try:
contacts = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
contacts = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
contacts = paginator.page(paginator.num_pages) return render(request, 'list.html', {'contacts': contacts})
后端处理
{% for contact in contacts %}
{# Each "contact" is a Contact model object. #}
{{ contact.full_name|upper }}<br />
...
{% endfor %} <div class="pagination">
<span class="step-links">
{% if contacts.has_previous %}
<a href="?page={{ contacts.previous_page_number }}">previous</a>
{% endif %} <span class="current">
Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
</span> {% if contacts.has_next %}
<a href="?page={{ contacts.next_page_number }}">next</a>
{% endif %}
</span>
</div>
前端展示
2、添加分页全局变量kingadmin.py
class CustomerAdmin(BaseAdmin):
list_display = ('id','name','qq','consultant','source','consult_content','status','data')
list_filter = ('source','status','consultant')
search_fields = ('qq','name')
list_editable = ('status',)
list_per_page = 2
3、处理函数views.py
def filter_querysets(request,model): #过滤
condtions = {}
for k,v in request.GET.items():
if v and k !='page':
condtions[k] = v
querysets =model.objects.filter(**condtions) return querysets,condtions from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.shortcuts import render def listing(request,admin_obj): paginator = Paginator(admin_obj.querysets, admin_obj.list_per_page) # Show 25 contacts per page
page = request.GET.get('page')
try:
contacts = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
contacts = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
contacts = paginator.page(paginator.num_pages) return contacts def table_data_list(request,app_name,model_name): #重新改造函数,加上过滤条件
# print(request.GET)
admin_obj = site.registered_sites[app_name][model_name]
model = admin_obj.model
admin_obj.querysets,admin_obj.condtions = filter_querysets(request,model)
print('before',admin_obj.querysets)
admin_obj.querysets = listing(request,admin_obj)
print('after',admin_obj.querysets) return render(request,"kingadmin/table_data_list.html",locals()) # locals 传入局部变量
4、kingadmin_tags.py
@register.simple_tag()
def generate_filter_url(admin_obj):
url = ""
for k,v in admin_obj.condtions.items():
url += "&%s=%s"%(k,v) return url
5、table_data_list.html
tfoot>
<nav aria-label="...">
<ul class="pagination">
<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a></li>
{% for page in admin_obj.querysets.paginator.page_range %}
{% if page == admin_obj.querysets.number %}
<li class="active">
{% else %}
<li >
{% endif %}
<a href="?page={{ page }}{% generate_filter_url admin_obj %}">{{ page }} <span class="sr-only">(current)</span></a>
</li>
{% endfor %}
</ul>
</nav>
</tfoot>
显示效果:
过滤、排序、分页组合
1、在原views.py上新增:
# 添加排序
def get_orderby(request,querysets): #排序
orderby_fieid = request.GET.get('o')
if orderby_fieid:
querys_res = querysets.order_by(orderby_fieid)
else:
querys_res = querysets return querys_res # 过滤修改
def filter_querysets(request,model): #过滤
condtions = {}
except_list = ["page",'o']
for k,v in request.GET.items():
if k in except_list:continue
if v:
condtions[k] = v
querysets =model.objects.filter(**condtions) return querysets,condtions # 分页添加
def listing(request,admin_obj):
querys_res = get_orderby(request, admin_obj.querysets)
2、自定义simple_tag
@register.simple_tag()
def generate_filter_url(admin_obj,request=None):
url = ""
if request:
if request.GET.get('o'):
url += "&o=%s" % request.GET.get('o')
for k,v in admin_obj.condtions.items():
url += "&%s=%s"%(k,v) return url @register.simple_tag
def get_orderby_key(request,column):
current_order_by_key = request.GET.get('o')
if current_order_by_key:
if current_order_by_key == column:
if column.startswith('-'):
column.strip("-")
else:
column = "-%s"%column
return column
else:
return column @register.simple_tag
def display_order_by_icon(request,column):
current_order_by_key = request.GET.get('o')
if current_order_by_key:
if current_order_by_key.strip('-') == column:
if current_order_by_key.startswith('-'):
icons = '''<span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>'''
else:
icons = '''<span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span>''' return mark_safe(icons) return ' '
3、html前端页面
// 过滤时添加排序
<form>
{% for filter_column in admin_obj.list_filter %}
<div class="col-lg-3">
{{ filter_column }}:{% get_filter_field filter_column admin_obj %}
</div>
{% endfor %}
<input type="submit" class="btn btn-success" value="过滤">
<input type="hidden" name="o" value="{{ request.GET.o }}"> //过滤时加上排序
</form> // 排序时加上过滤
{% for column in admin_obj.list_display %}
<th>
// 排序时加上过滤
<a href="?o={% get_orderby_key request column %}{% generate_filter_url admin_obj %}"> {{ column }}</a>
{% display_order_by_icon request column %}
</th>
{% endfor %} // 分页时加上过滤和排序
{% for page in admin_obj.querysets.paginator.page_range %}
{% if page == admin_obj.querysets.number %}
<li class="active">
{% else %}
<li >
{% endif %}
// 分页时加上排序和过滤
<a href="?page={{ page }}{% generate_filter_url admin_obj request%}">{{ page }} <span class="sr-only">(current)</span></a>
</li>
{% endfor %}
点击过滤或排序时页面恢复到第一页
搜索
1、views.py处理文件
# 添加搜索函数 注意顺序 def get_search(request,admin_obj):
search_content = request.GET.get('q')
condition = Q()
condition.connector = 'OR'
if search_content:
for column in admin_obj.search_fields:
condition.children.append(("%s__contains"%column,search_content)) querysets = admin_obj.querysets.filter(condition)
else:
querysets = admin_obj.querysets
return querysets def table_data_list(request,app_name,model_name): #重新改造函数,加上过滤条件 admin_obj = site.registered_sites[app_name][model_name]
model = admin_obj.model admin_obj.querysets,admin_obj.condtions = filter_querysets(request,model) #加过滤条件 admin_obj.querysets = get_search(request,admin_obj) # 搜索 admin_obj.querysets = listing(request,admin_obj) #分页 return render(request,"kingadmin/table_data_list.html",locals()) # locals 传入局部变量
2、自定义simple_tag
@register.simple_tag()
def generate_filter_search(request):
search_content = request.GET.get('q')
url = ""
if search_content:
url = "&q=%s"%search_content return url
3、前端html页面
过滤时的from
<form>
{% for filter_column in admin_obj.list_filter %}
<div class="col-lg-3">
{{ filter_column }}:{% get_filter_field filter_column admin_obj %}
</div>
{% endfor %}
<input type="submit" class="btn btn-success" value="过滤">
{# //过滤时加上排序#}
<input type="hidden" name="o" value="{{ request.GET.o }}">
<br/>
<input type="text" name="q" value="{{ request.GET.q }}">
</form> 排序
{% for column in admin_obj.list_display %}
<th>
{# // 排序时加上过滤#}
<a href="?o={% get_orderby_key request column %}{% generate_filter_search request %}{% generate_filter_url admin_obj %}"> {{ column }}</a>
{% display_order_by_icon request column %}
</th>
{% endfor %} 分页
<a href="?page={{ page }}{% generate_filter_search request %}{% generate_filter_url admin_obj request%}">{{ page }} <span class="sr-only">(current)</span></a>
页面显示:
数据修改
1、kingadmin下创建forms.py
from django import forms def CreateModelForm(admin_obj): # 动态生成modelfrom
class Meta:
model = admin_obj.model
fields = "__all__" dynamic_model_form = type("DynamicModelForm",(forms.ModelForm,),{'Meta':Meta}) return dynamic_model_form
2、views.py处理函数
from kingadmin import forms
def table_change(request,app_name,model_name,id):
admin_obj = site.registered_sites[app_name][model_name]
obj = admin_obj.model.objects.filter(id=id).first() model_form = forms.CreateModelForm(admin_obj)
obj_form = model_form(instance=obj) return render(request,'kingadmin/table_change.html',locals())
3、html文件
{% extends "kingadmin/index.html" %} {% load kingadmin_tags %} {% block right-container-content %}
{{ obj_form }}
{% endblock %}
table_change.html
显示视图:
修改完善
1、html文件
{% extends "kingadmin/index.html" %} {% load kingadmin_tags %} {% block right-container-content %}
<div class="row" style="margin-bottom: 20px" >
<ol class="breadcrumb">
<li><a href="/kingadmin/">Home</a></li>
<li><a href="/kingadmin/{% get_app_name admin_obj.model %}/">{% get_app_name admin_obj.model %}</a></li>
<li ><a href="/kingadmin/{% get_app_name admin_obj.model %}/{% get_model_name admin_obj.model %}/">{% get_model_verbose_name admin_obj.model%} </a></li>
<li class="active">{{ obj_form.instance }}</li>
</ol> <h4>Change {% get_model_verbose_name admin_obj.model %}</h4>
</div> <form class="form-horizontal" method="post" onsubmit="return BeforeFormSubmit(this);">{% csrf_token %}
{% for field in obj_form %}
<div class="form-group">
<label class="col-sm-2 " style="font-weight: normal">
{% if field.field.required %}
<b>{{ field.label }}</b>
{% else %}
{{ field.label }}
{% endif %}
</label>
<div class="col-sm-10">
<span style="color: red;">{{ field.errors }}</span>
{{ field }}
</div>
</div>
{% endfor %}
<input type="submit" value="Save" class="pull-right btn btn-info" >
</form>
{% endblock %}
table_data_list.html
2、froms.py
from django import forms def CreateModelForm(admin_obj): # 动态生成modelfrom
class Meta:
model = admin_obj.model
fields = "__all__" def __new__(cls, *args, **kwargs):
# print("base fields",cls.base_fields)
for field_name, field_obj in cls.base_fields.items():
print(field_name,dir(field_obj))
field_obj.widget.attrs['class'] = 'form-control'
# field_obj.widget.attrs['maxlength'] = getattr(field_obj,'max_length' ) if hasattr(field_obj,'max_length') \
# else ""
# if field_name in admin_obj.readonly_fields:
# field_obj.widget.attrs['disabled'] = True return forms.ModelForm.__new__(cls) dynamic_model_form = type("DynamicModelForm",(forms.ModelForm,),{'Meta':Meta})
setattr(dynamic_model_form,"__new__",__new__)
return dynamic_model_form
3、views.py处理文件
from kingadmin import forms
def table_change(request,app_name,model_name,id):
admin_obj = site.registered_sites[app_name][model_name]
obj = admin_obj.model.objects.filter(id=id).first()
model_form = forms.CreateModelForm(admin_obj) if request.method == "GET":
obj_form = model_form(instance=obj)
elif request.method == "POST":
obj_form = model_form(instance=obj, data=request.POST)
if obj_form.is_valid():
obj_form.save() return render(request, "kingadmin/table_change.html", locals())
表单添加
1、html文件
{% extends "kingadmin/index.html" %} {% load kingadmin_tags %} {% block right-container-content %}
<div class="row" style="margin-bottom: 20px" >
<ol class="breadcrumb">
<li><a href="/kingadmin/">Home</a></li>
<li><a href="/kingadmin/{% get_app_name admin_obj.model %}/">{% get_app_name admin_obj.model %}</a></li>
<li ><a href="/kingadmin/{% get_app_name admin_obj.model %}/{% get_model_name admin_obj.model %}/">{% get_model_verbose_name admin_obj.model%} </a></li>
<li class="active">Add {% get_model_name admin_obj.model %}</li>
</ol> <h4>Change {% get_model_verbose_name admin_obj.model %}</h4>
</div> <form class="form-horizontal" method="post" onsubmit="return BeforeFormSubmit(this);">{% csrf_token %}
{% for field in obj_form %}
<div class="form-group">
<label class="col-sm-2 " style="font-weight: normal">
{% if field.field.required %}
<b>{{ field.label }}</b>
{% else %}
{{ field.label }}
{% endif %}
</label>
<div class="col-sm-10">
<span style="color: red;">{{ field.errors }}</span>
{{ field }}
</div>
</div>
{% endfor %}
<input type="submit" value="Save" class="pull-right btn btn-info" >
</form>
{% endblock %}
table_add.html
2、froms.py文件
from django import forms def CreateModelForm(admin_obj): # 动态生成modelfrom
class Meta:
model = admin_obj.model
fields = "__all__" def __new__(cls, *args, **kwargs):
# print("base fields",cls.base_fields)
for field_name, field_obj in cls.base_fields.items():
# print(field_name,dir(field_obj))
field_obj.widget.attrs['class'] = 'form-control'
# field_obj.widget.attrs['maxlength'] = getattr(field_obj,'max_length' ) if hasattr(field_obj,'max_length') \
# else ""
if field_name in admin_obj.readonly_fields:
field_obj.widget.attrs['disabled'] = True return forms.ModelForm.__new__(cls) dynamic_model_form = type("DynamicModelForm",(forms.ModelForm,),{'Meta':Meta})
setattr(dynamic_model_form,"__new__",__new__)
return dynamic_model_form
3、views.py处理文件
def table_add(request,app_name,model_name):
admin_obj = site.registered_sites[app_name][model_name]
model_form = forms.CreateModelForm(admin_obj)
if request.method == "GET":
obj_form = model_form() if request.method == "POST":
obj_form = model_form(data=request.POST)
if obj_form.is_valid():
obj_form.save()
if not obj_form.errors:
return redirect('/kingadmin/%s/%s'%(app_name,model_name)) return render(request, "kingadmin/table_add.html", locals())
增加readonly_fields字段
1、forms.py文件修改
from django import forms def CreateModelForm(admin_obj): # 动态生成modelfrom
class Meta:
model = admin_obj.model
fields = "__all__" def __new__(cls, *args, **kwargs):
# print("base fields",cls.base_fields)
for field_name, field_obj in cls.base_fields.items():
# print(field_name,dir(field_obj))
field_obj.widget.attrs['class'] = 'form-control'
# field_obj.widget.attrs['maxlength'] = getattr(field_obj,'max_length' ) if hasattr(field_obj,'max_length') \
# else ""
if field_name in admin_obj.readonly_fields:
field_obj.widget.attrs['disabled'] = True return forms.ModelForm.__new__(cls) def default_clean(self):
# print("default clean:",self)
for field in admin_obj.readonly_fields:
print("readonly", field, self.instance)
field_val_from_db = getattr(self.instance, field)
field_val = self.cleaned_data.get(field)
if field_val_from_db == field_val:
print("field not change ")
else: # 被篡改了
self.add_error(field, ' "%s" is a readonly field ,value should be "%s" ' % (field, field_val_from_db)) print("cleaned data:", self.cleaned_data) dynamic_model_form = type("DynamicModelForm",(forms.ModelForm,),{'Meta':Meta})
setattr(dynamic_model_form,"__new__",__new__)
setattr(dynamic_model_form,"clean",default_clean)
return dynamic_model_form
添加action动作
1、kingadmin.py
class CustomerAdmin(BaseAdmin):
list_display = ('id','name','qq','consultant','source','consult_content','status','data')
list_filter = ('source','status','consultant')
search_fields = ('qq','name')
list_editable = ('status',)
readonly_fields = ('name',)
list_per_page = 5
actions = ["change_status", ] def change_status(self, request, querysets):
print("changeing status", querysets)
querysets.update(status=1) change_status.short_description = "改变报名状态" class EnrollmentAdmin(BaseAdmin):
list_display = ('customer','class_grade','enrollment_date') site.register(models.Customer,CustomerAdmin)
site.register(models.FollowUpRecord)
site.register(models.Enrollment,EnrollmentAdmin)
2、views.py处理函数
def table_data_list(request,app_name,model_name): #重新改造函数,加上过滤条件
admin_obj = site.registered_sites[app_name][model_name] if request.method == "POST": action = request.POST.get("action_select")
selected_ids = request.POST.get("selected_ids")
selected_ids = json.loads(selected_ids)
print("action:",selected_ids,action)
selected_objs = admin_obj.model.objects.filter(id__in=selected_ids) action_func = getattr(admin_obj,action)
action_func(request,selected_objs) model = admin_obj.model admin_obj.querysets,admin_obj.condtions = filter_querysets(request,model) #加过滤条件 admin_obj.querysets = get_search(request,admin_obj) # 搜索 admin_obj.querysets = listing(request,admin_obj) #分页 return render(request,"kingadmin/table_data_list.html",locals()) # locals 传入局部变量
3、table_data_list.html
{% extends 'kingadmin/index.html' %}
{% load kingadmin_tags %} {% block right-container-content %}
<ol class="breadcrumb">
<li><a href="/kingadmin/">Home</a></li>
<li><a href="/kingadmin/{% get_app_name admin_obj.model %}/">{% get_app_name admin_obj.model %}</a></li>
<li class="active">{% get_model_verbose_name admin_obj.model%} </li>
<li class="pull-right">
<a href="add/"><input type="button" class="btn btn-sm btn-success" value="+Add"></a>
</li>
</ol> <h4>{% get_model_verbose_name admin_obj.model %}</h4>
{# {{ admin_obj.list_filter }}#} {% if admin_obj.list_filter %}
<div class="row">
<form>
{% for filter_column in admin_obj.list_filter %}
<div class="col-lg-3">
{{ filter_column }}:{% get_filter_field filter_column admin_obj %}
</div>
{% endfor %}
<input type="submit" class="btn btn-success" value="过滤">
{# //过滤时加上排序#}
<input type="hidden" name="o" value="{{ request.GET.o }}">
<br/>
<input type="text" name="q" value="{{ request.GET.q }}">
</form> <form method="post" onsubmit="return ActionValidation(this)">{% csrf_token %}
<select name="action_select"> {% get_admin_actions admin_obj %}
</select>
<input type="submit" value="执行">
</form> </div>
{% endif %} <table class="table table-hover">
<thead>
<tr>
<th><input type="checkbox" onclick="SelectAll(this)" /></th>
{% for column in admin_obj.list_display %}
<th>
{# // 排序时加上过滤#}
<a href="?o={% get_orderby_key request column %}{% generate_filter_search request %}{% generate_filter_url admin_obj %}"> {{ column }}</a>
{% display_order_by_icon request column %}
</th>
{% endfor %}
</tr>
</thead> <tbody> {% for obj in admin_obj.querysets %}
<tr>
<td>
<input tag="obj_checkbox" type="checkbox" value="{{ obj.id }}" />
</td>
{% build_table_row admin_obj obj %}
</tr>
{% endfor %}
</tbody>
</table>
<tfoot>
<nav aria-label="...">
<ul class="pagination">
<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</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 ==){
alert("must select at least one object to run the action!");
return false;
} var selected_objs_ele = "<input name='selected_ids' type='hidden' value=" + JSON.stringify(selected_objs) + " >" ;
$(form_ele).append(selected_objs_ele); return true; } </script>
{% endblock %}
html
4、simple_tag
@register.simple_tag
def get_admin_actions(admin_obj): options = "<option class='form-control' value='-1'>-------</option>"
actions = admin_obj.default_actions + admin_obj.actions for action in actions:
action_func = getattr(admin_obj,action)
if hasattr(action_func,"short_description"):
action_name = action_func.short_description
else:
action_name = action
options += """<option value="{action_func_name}">{action_name}</option> """.format(action_func_name=action,
action_name=action_name) return mark_safe(options)
Python开发【Django】:重构Admin的更多相关文章
- Python学习---django之admin简介
Django之admin简介 参考文献:http://www.admin10000.com/document/2220.html Djaogo为什么url可以匹配url.py里面的路径呢? 我们打 ...
- Python开发【Django】:Admin配置管理
Admin创建登录用户 数据库结构表: from django.db import models # Create your models here. class UserProfile(models ...
- Python开发入门与实战2-第一个Django项目
2.第一个Django项目 上一章节我们完成了python,django和数据库等运行环境的安装,现在我们来创建第一个django project吧,迈出使用django开发应用的第一步. 2.1.创 ...
- Python开发【第二十二篇】:Web框架之Django【进阶】
Python开发[第二十二篇]:Web框架之Django[进阶] 猛击这里:http://www.cnblogs.com/wupeiqi/articles/5246483.html 博客园 首页 ...
- Python开发【第二十一篇】:Web框架之Django【基础】
Python开发[第二十一篇]:Web框架之Django[基础] 猛击这里:http://www.cnblogs.com/wupeiqi/articles/5237704.html Python之 ...
- Python开发【第十八篇】Web框架之Django【基础篇】
一.简介 Python下有许多款不同的 Web 框架,Django 是重量级选手中最有代表性的一位,许多成功的网站和APP都基于 Django. Django 是一个开放源代码的Web应用框架,由 P ...
- python开发学习-day15(前端部分知识、web框架、Django创建项目)
s12-20160430-day15 *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: ...
- Python开发【Django】:Model操作(一)
Django ORM基本配置 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去 ...
- 《Python高效开发实战》实战演练——开发Django站点1
6.2 实战演练:开发Django站点 用Django开发网站需要遵循Django的一套开发流程.本节通过建立一个消息录入页面演示Django的开发流程及相关技术. 6.12.1 建立项目 在进行D ...
- [Python] 利用Django进行Web开发系列(一)
1 写在前面 在没有接触互联网这个行业的时候,我就一直很好奇网站是怎么构建的.现在虽然从事互联网相关的工作,但是也一直没有接触过Web开发之类的东西,但是兴趣终归还是要有的,而且是需要自己动手去实践的 ...
随机推荐
- 怎么成为asp.net大神!!!!!!!!!!!!!!!!!!!怎么成为asp.net大神!!!!!!!!!!!!!!!!!!!
怎么成为asp.net大神!!!!!!!!!!!!!!!!!!!怎么成为asp.net大神!!!!!!!!!!!!!!!!!!!怎么成为asp.net大神!!!!!!!!!!!!!!!!!!!怎么成为 ...
- 简单html弹窗
css: <style type="text/css"> .moneyrecord { display:none; border:0.5em solid #00AAEE ...
- 小技巧处理div内容溢出
前几天遇到一个问题,代码是这样一个层次: <div class="province"> <ul> <li>1</li& ...
- MathType在字母上加虚线的方法
在数学中根据不同的需要,会对其中的公式或变量字母作不同的标记.这些标记在用MathType编辑数学公式时同样也要准确地编辑出来,例如在字母上方加虚线.这种数学样式在使用时也是根据自己的数学问题来使用的 ...
- 数据挖掘Apriori算法——学习笔记
关联规则.频繁项集.支持度.置信度 关联规则挖掘: 一起购买的商品 支持度(support) 支持度会随着物品增多而减小.因为是同时购买的比率. 置信度(Confidence) 频繁且强规则,有一定意 ...
- 关于NoSQL与SQL的区别
简单说来:sql是关系型数据库的结构化查询语言,而nosql,一般代指菲关系型数据库,sql语句就不能用来,不过有些有leisql的查询语言,且nosql数据库没有统一的查询语言. 相关参考文章阅读: ...
- 搭建LNMP+CI环境
首先搭建 LNMP 的服务器环境 安装 Nginx, MySQL 和 PHP 软件包,执行以下命令 yum install -y nginx mariadb-server mariadb php ph ...
- linux命令之用户和用户组
知识点: 1.-rwx--x--x (711) 只有所有者才有读,写,执行的权限,组群和其他人只有执行的权限 2.将root用户添加到supergroup用户组 groupadd supergroup ...
- 什么是"抓包"?怎样"抓包"?
你是网络管理员吗?你是不是有过这样的经历:在某一天的早上你突然发现网络性能急剧下降,网络服务不能正常提供,服务器访问速度极慢甚至不能访问,网络交换机端口指示灯疯狂地闪烁.网络出口处的路由器已经处于满负 ...
- <转>Logistic回归总结
转自http://blog.csdn.net/dongtingzhizi/article/details/15962797 当我第一遍看完台大的机器学习的视频的时候,我以为我理解了逻辑回归,可后来越看 ...