自定义django admin及其界面
1.在项目目录下新创建一个app,命名为kingadmin,在templates目录下新建kingadmin目录,用来存放相关页面的模板文件,新建一个templatetags目录,用来存放处理前端模板数据的python函数。
项目/kingadmin/templates/kingadmin/base.html 最基础的模板,存放的js与css
<!DOCTYPE html> <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=""> {# meta全部保留,IE浏览器相关的可要可不要,图标与css也要全部保留#} <link rel="icon" href="http://v3.bootcss.com/favicon.ico"> <title>王腾的个人站点</title> <link href="/static/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/css/dashboard.css" rel="stylesheet"> {% block header-resources %} {% endblock %} {# 这里留一个block块,可以方便其他网页继承时进行扩展 来添加自定义样式#} </head> <body> {% block body %} {% endblock %} {# 这里留一个block body块,可以方便其他网页继承时进行扩展 在body里添加自定义的内容#} <script src="/static/js/jquery.min.js"></script> <script src="/static/js/bootstrap.min.js"></script> <script src="/static/js/holder.min.js"></script> {# 这些js全部保留,js的路径static是settings.py中STATIC_URL = '/static/'对应的STATIC_URL,而不是实际的目录名#} <script> {# 这里是自定义js,点击相应按钮时,按钮变颜色#} $(document).ready(function () { var current_url = "{{ request.path }}"; $('.nav-sidebar a[href="{{ request.path }}"]').parent().addClass('active'); }) </script> </body></html>
项目/kingadmin/templates/kingadmin/index.html 页面框架
{% extends 'base.html' %} {#这里写继承base.html#} {% block body %} {# 这里在block body里自定义body的内容,要注意写上block body#} {% block nav-bar %} {# 这个block块是页面最上边的导航栏,为了其他页面可自定制导航栏,这里弄一个块,当其它页面写上 {% block nav-bar %}{% endblock %}时#} {# 其它页面的导航栏位置就不会显示模板的导航栏了#} <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/#">后台管理</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="http://v3.bootcss.com/examples/dashboard/#" 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="http://v3.bootcss.com/examples/dashboard/#">首页</a></li> <li><a href="/logout">注销</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 %} {# 这里写一个左边栏block块,也是为了其他页面可以自定制#} <div class="col-sm-3 col-md-2 sidebar"> <ul class="nav nav-sidebar"> {% block side-bar-menu %} {% for role in request.user.userprofile.roles.all %} <h3></h3> {# <li class="active"><a href="http://v3.bootcss.com/examples/dashboard/#">{{ role }}<span class="sr-only">(current)</span></a></li>#} {% for menu in role.menus.all %} <li> <a href="{% if menu.url_type == 0 %}{% url menu.url_name %}{% else %}{{ menu.url_name }} {# 这里的{% url menu.url_name %}就是取得数据库中的url_name,并且将这个url_name与urls.py中的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> <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 %}
项目/kingadmin/templates/kingadmin/app_index.html app页面
{% extends 'kingadmin/index.html' %} {% load kingadmin_tags %} {#这里要使用tags的原因是:前端模板不允许变量有下划线,但是为了获得表名,python函数_mtea是有下划线的,所有要用tags#} {% block right-container-content %} {% for app,app_tables in size.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> {#这里设置相关链接的url,这里要使用tags的原因是:前端模板不允许变量有下划线,但是为了获得表名,python函数_mtea是有下划线的,所有要用tags#} <th scope="row"><a href="/kingadmin/{% get_app_name admin_class.model %}/{% get_model_name admin_class.model %}">{% get_model_verbose_name admin_class.model %}</a> {{ admin_class }}</th> </tr> {% endfor %} </tbody> </table> {% endfor %} {% endblock %}
项目/kingadmin/templates/kingadmin/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> {# aadmin_obj其实就是注册表的表对象,在views函数里#} {% 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 %}
项目/kingadmin/templatetags/kingadmin_tags.py 标签函数,用来存放处理前端数据的标签函数
#!/usr/bin/python # -*- coding:utf-8 -*- # author:wt 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 if model_obj._meta.verbose_name else model_obj._meta.verbose_name_plural if not model_name: model_name = model_obj._meta.model_name print('ssss',model_name) return model_name @register.simple_tag def get_app_name(model_obj): print('label',model_obj._meta.app_label) return model_obj._meta.app_label # 获取app名 @register.simple_tag def get_model_name(model_obj): # 获取表的英文名, print('model_name',model_obj._meta.model_name) return model_obj._meta.model_name @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: #判断column_obj是否是表中的choice字段,用choice属性,如果是choice字段,则返回真 get_column_data = getattr(obj,'get_%s_display'%column) column_data = get_column_data() else: column_data = getattr(obj,column) #获取对象obj的属性column对应的值,这里的column就是表中的字段 td_ele = """<td>%s""" % column_data row_ele += td_ele return mark_safe(row_ele)
2.以下函数全都创建在项目/kingadmin/下
app_config.py 自动找到settings.py文件,并将其中的app模块全部导入
#!/usr/bin/python # -*- coding:utf-8 -*- # author:wt from django import conf # 导入conf模块 conf.settings # 可以自动找到项目的配置文件 for app in conf.settings.INSTALLED_APPS: try: print(__import__('%s.kingadmin' % app)) # 自动导入相关模块 except ImportError as e: print('app has no import')
base_admin.py 主要的admin函数
#!/usr/bin/python # -*- coding:utf-8 -*- # author:wt class AdminRegisterException(Exception): # 处理注册app时发生异常 def __init__(self,msg): self.message = msg class BaseAdmin(object): # 定义过滤条件,就是如果将表中的部分字段写在下边的括号里,那么将按这几个字段进行过滤,如:list_display = ('qq','name'),按qq和name过滤 list_display = () list_filter = () search_fields = () list_editable = () class AdminSite(object): def __init__(self): self.registered_sites = {} def registed(self,model,admin_class=None): app_name = model._meta.app_label # 获取app名 model_name = model._meta.model_name # 获取app的表名 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 registerred!" % (app_name,model_name)) if not admin_class: #则使用BaseAdmin admin_class = BaseAdmin admin_obj = admin_class() # 实例化 admin_obj.model = model # 再给BaseAdmin类添加一个属性model,这样就可以获取到表的model对象了,进而可以通过model._meta.verbose_name获取到表的中文名了 self.registered_sites[app_name][model_name] = admin_obj # 将表对象放进字典 site = AdminSite()
views.py 数据处理函数
from django.shortcuts import render from django import conf from kingadmin import app_config from kingadmin import base_admin # Create your views here. def app_index(request): print(base_admin.site.registered_sites) return render(request,'kingadmin/app_index.html',{'size':base_admin.site}) def table_data_list(request,app_name,model_name): admin_obj = base_admin.site.registered_sites[app_name][model_name] # admin_obj其实就是注册表的表对象 admin_obj.querysets = admin_obj.model.objects.all() # 给admin_obj添加自定义属性querysets return render(request,'kingadmin/table_data_list.html',locals()) # locals()返回全部的admin_obj,
urls.py 路由函数
from django.conf.urls import url,include from django.contrib import admin from kingadmin import views urlpatterns = [ # url(r'^', views.dashboard), url(r'^$', views.app_index), url(r'^(\w+)/(\w+)/$', views.table_data_list), ]