46 - 自定义CURD插件
知识回顾
admin.site.register(models.UserInfo) URL: /admin/app01/userinfo/ /admin/app01/userinfo/add/ /admin/app01/userinfo/1/change/ /admin/app01/userinfo/1/delete/ admin.site.register(models.UserType) URL: /admin/app01/usertype/ /admin/app01/usertype/add/ /admin/app01/usertype/1/change/ /admin/app01/usertype/1/delete/ 结论: 先注册类 循环注册的所有的类,每个类创建N个url,如下: /admin/app01/userinfo/ obj1.changelist_view /admin/app01/userinfo/add/ obj1.add_view /admin/app01/userinfo/(\d+)/delete/ obj1.delete_view /admin/app01/userinfo/(\d+)/change/ obj1.change_view self.model=models.UserInfo /admin/app01/usertype/ obj2.changelist_view /admin/app01/usertype/add/ obj2.add_view /admin/app01/usertype/(\d+)/delete/ obj2.delete_view /admin/app01/usertype/(\d+)/change/ obj2.change_view self.model=models.UserType 自定义功能: from django.contrib import admin from django.contrib.admin import ModelAdmin from . import models from django.shortcuts import HttpResponse class UserInfoModelAdmin(ModelAdmin): def changelist_view(self, request, *args,**kwargs): return HttpResponse('用户列表') admin.site.register(models.UserInfo,UserInfoModelAdmin) 29个功能 重要原理: - admin原理(自定义) - admin使用
自定义CURD插件
- 自定义CURD
Django Admin:根据配置文件的修改,完成CURD定制任务
自定义:根据配置文件的修改,完成CURD定制任务
知识点
1,启动文件执行顺序及制作启动文件
启动文件执行顺序:先注册(admin.site.register),然后在分配url(admin.site.urls)
制作启动文件Q:为什么在每个app里的admin.py可以中进行admin.site.register之后,在django启动之后就可以被django识别呢?
A:查看app01的源码:
from django.contrib import admin # Register your models here.
继续查看admin的源码:
from django.utils.module_loading import autodiscover_modules def autodiscover(): autodiscover_modules('admin', register_to=site) # register_to=site参数可以不传
原理是在admin类中如上autodiscover_modules之后,就会去所有的app中找admin.py并执行。
所以我们要创建一个公共的CURD组件,并且能够被django识别,也需要如上注册。步骤如下:
- 创建app【arya是一个类似于admin的自定义CURD插件】
- 找到app.py【arya/apps.py】
from django.apps import AppConfig class AryaConfig(AppConfig): name = 'arya' def ready(self): from django.utils.module_loading import autodiscover_modules autodiscover_modules('arya')
- settings.py
INSTALLED_APPS = [ ... 'arya.apps.AryaConfig', # 不要写'arya'这种方式注册 .... ]
结果:django启动后,会自动去所有的app中找 arya.py 执行,所以我们可以在每个app【指的是业务app,可以有多个】下都放一个arya.py的文件
2,单例模式(基于python文件导入特性)
上述中的v1.site就是单例模式
示例1:
v1.py
class Foo: def __init__(self): self._ret = [] def add(self,v): self._ret.append(v) # 实例1 obj1 = Foo() obj1.add(666) # 实例2 obj2 = Foo() print(obj2._ret)
obj1和obj2是两个实例,所以打印结果是[]
示例2:
v1.py
class Foo: def __init__(self): self._ret = [] def add(self,v): self._ret.append(v) site = Foo()
v2.py
import v1 print(v1.site._ret) v1.site.add(666) import v1 print(v1.site._ret)
运行结果为
[] [666]
解释:这个就是单例模式,python 多次导入同一模块,只有第一次生效,下面的用的是上面的结果。
3,你真的了解include吗?
查include的源码
def include(arg, namespace=None, app_name=None): ...... return (urlconf_module, app_name, namespace)
include返回的是一个元组,且元组的第一个元素是列表
补充,如下函数返回的也是一个元组
def func(): return 1,2,3 ret = func() print(ret)
执行结果:
(1, 2, 3)
实现的功能
# 1. 列表显示列相关
list_display = ['host','port']
# 2. 添加按钮相关(AryaConfig中默认的是False)
show_add = True
# 3. ModelForm,如上定义了添加和修改的时候ModelForm只对host字段生效,且错误消息为'host不能为空'
model_form_class = UserInfoModelForm (提前定义这个自定义的ModelForm)
# 4. 指定可以搜索哪几列,并指定host是模糊搜索,port是精确搜索
search_list = ['host__contains','port']
# 5.分页配置(AryaConfig中默认的是每页显示10个,最多显示11个页面,如果想单独设置应该也可以(子类配置优先))
# 6. 自定义批量Action
class UserInfoConfig(v1.AryaConfig): list_display = ['name','pwd','id','email'] model_form_class = UserInfoModelForm search_list = ['name__contains','pwd__contains'] def multi_delete(self,request): pk_list = request.POST.getlist('pk') # [1,2] self.model_class.objects.filter(id__in=pk_list).delete() multi_delete.text = "批量删除阿" def multi_init(self,request): pk_list = request.POST.getlist('pk') # [1,2] self.model_class.objects.filter(id__in=pk_list).delete() multi_init.text = "初始化" actions = [multi_delete,multi_init] v1.site.register(models.UserInfo,UserInfoConfig)
补充知识点:
def func1():
pass
func1.text = "批量删除"
print(func1)
print(func1.__name__)
print(func1.text)
代码实现
目录结构如下

service/v1.py
from django.shortcuts import render, redirect from django.utils.safestring import mark_safe from django.urls import reverse from django.forms import ModelForm import copy from ..utils.page import Pagination class ChangeList(object): """ 专门处理列表页面所有的功能 """ def __init__(self, config, queryset): # self,queryset self.config = config # 其实就是aryaconfig对象 # config是形参,实参self代表的是由UserInfoConfig(或UserTypeConfig)类实例化出来的对象 self.q_value = config.request.GET.get('q', '') # 获取要查询的关键字 self.list_display = config.get_list_display() # table_header、table_body会用到这个属性 self.show_add = config.get_show_add() # 封装到cl对象中,前端根据这个做判断 self.add_url = config.reverse_add_url() # 封装到cl对象中,前端根据这个做判断 # 定义搜索后哪些字段及搜索规则,如:[name__contains,pwd] self.search_list = config.get_search_list() self.actions = config.get_actions() # 处理分页数据 request = config.request query_params = copy.deepcopy(request.GET) # request.GET是QueryDict的类型 # 为什么要copy ?因为搜索后,点击编辑后保存后,还应该返回到原来的页面,这个过程要修改request.GET current_page = request.GET.get('page', 1) # 当前页码 per_page = config.per_page # 每页显示数据条数 pager_page_count = config.pager_page_count # 页面上最多显示的页码数量 all_count = queryset.count() # 数据库中总条数 # http://127.0.0.1:8000/index.html/?page=17# 中的/index.html/ base_url = config.reverse_list_url() page_obj = Pagination( current_page, all_count, base_url, query_params, per_page, pager_page_count) # table_body中用来显示 self.queryset = queryset[page_obj.start:page_obj.end] self.page_html = page_obj.page_html() def table_header(self): data = [] for str_func in self.list_display: if isinstance(str_func, str): val = self.config.model_class._meta.get_field( str_func).verbose_name else: val = str_func(self.config, is_header=True) # self.config.model_class._meta.get_field(str_func) 得到了字段,字段.verbose_name即字段的显示 # 固定用法,掌握即可 data.append(val) return data def table_body(self): table_data = [] for obj in self.queryset: row = [] for str_func in self.list_display: if isinstance(str_func, str): col = getattr(obj, str_func) else: col = str_func(self.config, obj) # 在外部执行的话(不用ChangeList封装)相当于是 # col = str_func(self,obj) # ##这块就是函数的主动传值!!!!! # 这里的self.config 和 实参 self等效 row.append(col) table_data.append(row) return table_data def action_options(self): # 前端会调用这个函数 data = [] for func in self.actions: # 这个self.actions的属性在上面定义 temp = {'value': func.__name__, 'text': func.text} data.append(temp) return data class AryaConfig(object): # 1. 列表显示列相关 list_display = [] def get_list_display(self): # self代表的是由UserInfoConfig(或UserTypeConfig)类实例化出来的对象 result = [] result.extend(self.list_display) # 对象.list_display先去当前类找【优先级高】,如果当前类没有定义再去父类(AryaConfig)中找 # 如果有编辑权限 result.append(AryaConfig.row_edit) # 如果有删除权限 result.append(AryaConfig.row_del) # checkbox是每行都需要的 result.insert(0, AryaConfig.row_checkbox) return result # 这些函数放在AryaConfig就是公共的,如果放在UserInfoConfig、UserTypeConfig....就是每个都得定义 # 当然如果在UserInfoConfig、UserTypeConfig再定义就会覆盖父类AryaConfig的方法 def row_del(self, row=None, is_header=None): if is_header: # 判断是否是表头,不是表头,则是表的列数据 return '删除' # 根据name反射生成删除的URL(app01_userinfo_delete) app = self.model_class._meta.app_label # app01 md = self.model_class._meta.model_name # model_name => md name = "arya:%s_%s_delete" % (app, md,) # arya:app01_userinfo_delete # 当存在namespace的时候,反射要用reverse(viewname='arya:app01_userinfo_delete') url = reverse(viewname=name, args=(row.id,)) # 因为url需要一个(\d+)的参数,所以需要传递args=(row.id,) return mark_safe("<a href='{0}'>删除</a>".format(url)) def row_edit(self, row=None, is_header=None): if is_header: return '编辑' # 根据name反射生成编辑的URL(app01_userinfo_change) app = self.model_class._meta.app_label md = self.model_class._meta.model_name name = "arya:%s_%s_change" % (app, md,) # arya:app01_userinfo_change url = reverse(viewname=name, args=(row.id,)) return mark_safe("<a href='{0}'>编辑</a>".format(url)) def row_checkbox(self, row=None, is_header=None): if is_header: return '选择' return mark_safe( "<input type='checkbox' value='{0}' />".format(row.id)) # 2. 添加按钮相关 show_add = False def get_show_add(self): if self.show_add: # 如果没有增加权限,否则返回False return self.show_add # 3. ModelForm model_form_class = None def get_model_form_class(self): """ 用户可以在arya.py中自定义ModelForm,然后将model_form_class配置为自己定义的ModelForm,如下: class UserInfoModelForm(ModelForm): class Meta: model = models.UserInfo fields = "__all__" # fields = ['name','pwd'] # exclude = ['name'] error_messages = { 'name':{ 'required':'用户名不能为空', }, 'pwd': { 'required': '密码不能为空', } } class UserInfoConfig(v1.AryaConfig): list_display = ['name','pwd','id','email'] model_form_class = UserInfoModelForm # 这里是重点哦~~~~ v1.site.register(models.UserInfo,UserInfoConfig) :return: """ if self.model_form_class: # self代表的是由UserInfoConfig(或UserTypeConfig)类实例化出来的对象 return self.model_form_class # 如果用户定义了,则使用用户定义的ModelForm,否则使用下面的DynamicModelForm class DynamicModelForm(ModelForm): class Meta: model = self.model_class fields = "__all__" # 自动为所有字段生成ModelForm return DynamicModelForm # 4. 模糊搜索 search_list = [] def get_search_list(self): # 定义搜索后哪些字段及搜索规则,如:[name__contains,pwd] rest = [] rest.extend(self.search_list) return rest # 5. 分页配置 # 每页显示10条数据 per_page = 10 # 页面上最多显示的页面个数 pager_page_count = 11 # 6. Action actions = [] def get_actions(self): result = [] result.extend(self.actions) # 可以自定义在arya中actions,但是这块老师笔记被删除了 return result def __init__(self, model_class, site): self.model_class = model_class # 比如model_class是UserInfo self.site = site @property def urls(self): from django.conf.urls import url # self.model_class # 代表UserInfo或UserGroup app = self.model_class._meta.app_label md = self.model_class._meta.model_name # app 、md 是url的name属性的唯一区别标识符 partterns = [ url( r'^$', self.changelist_view, name="%s_%s_list" % (app, md,)), url( r'^add/', self.add_view, name="%s_%s_add" % (app, md,)), url( r'^(\d+)/change/', self.change_view, name="%s_%s_change" % (app, md,)), url( r'^(\d+)/delete/', self.delete_view, name="%s_%s_delete" % (app, md,)), ] # 定义name属性,可以通过reverse的方式反查url return partterns # 反向生成URL相关 def reverse_add_url(self): app = self.model_class._meta.app_label md = self.model_class._meta.model_name name = "arya:%s_%s_add" % (app, md,) # arya:app01_userinfo_add url = reverse(viewname=name) return url def reverse_list_url(self): app = self.model_class._meta.app_label md = self.model_class._meta.model_name name = "arya:%s_%s_list" % (app, md,) # arya:app01_userinfo_list url = reverse(viewname=name) return url # 每个AryaConfig的对象都具有这些方法,所以注册后就会可以使用这些函数 # 列表页面 def changelist_view(self, request): # UserInfoConfig对象 = self # UserTypeConfig对象 = self self.request = request if request.method == "POST": action_item_name = request.POST.get( 'select_ac') # multi_init /multi_delete if action_item_name: func = getattr(self, action_item_name) func(request) from django.db.models import Q condition = Q() search_q = request.GET.get('q') # 定义搜索后哪些字段及搜索规则,如:[name__contains,pwd] search_list = self.get_search_list() if search_q and search_list: for field in search_list: temp = Q() temp.children.append((field, search_q)) condition.add(temp, 'OR') # condition = Q(Q(name__contains='xxx') OR Q(pwd='xx')) queryset = self.model_class.objects.filter(condition) cl = ChangeList(self, queryset) # 因为给'changelist.html'传的参数会比较多,所以都封装到ChangeList这个类中,然后传一个对象即可 return render(request, 'arya/changelist.html', {'cl': cl}) # 增加页面(利用ModelForm) def add_view(self, request): # self.model_class/ userinfo # self.model_class/ usertype model_form_cls = self.get_model_form_class() # 根据上面定义的函数获取model_form_class if request.method == "GET": form = model_form_cls() # 为所有字段生成Input框 return render(request, 'arya/add_view.html', {'form': form}) else: form = model_form_cls(data=request.POST) if form.is_valid(): # 表单数据验证通过 form.save() # save方法会直接将数据插入到数据库中 return redirect(self.reverse_list_url()) # 反向生成URL,跳转回列表页面 return render(request, 'arya/add_view.html', {'form': form}) # 修改页面(利用ModelForm) # ModelForm 生成表单+ 用户提交的语法检测 def change_view(self, request, nid): obj = self.model_class.objects.filter(pk=nid).first() # 获取到要修改的对象 if not obj: return redirect(self.reverse_list_url()) # 如果获取不到,则跳回到列表页面 model_form_cls = self.get_model_form_class() # 根据上面定义的函数获取model_form_class if request.method == 'GET': # 在Input框中显示默认值 form = model_form_cls(instance=obj) return render(request, 'arya/change_view.html', {'form': form}) else: form = model_form_cls(instance=obj, data=request.POST) # 使用instance + data 这种方式是更新原有记录,如果不使用这个,直接使用if分支中的form修改后提交则是新建 if form.is_valid(): # 表单数据验证通过 form.save() # save方法会request.POST中的数据直接更新到到数据库instance=user_obj的记录中 return redirect(self.reverse_list_url()) return render(request, 'arya/change_view.html', {'form': form}) # 删除页面 def delete_view(self, request, nid): obj = self.model_class.objects.filter(id=nid).first() # 获取到要删除的对象 if not obj: return redirect(self.reverse_list_url()) # 如果获取不到,则跳回到列表页面 if request.method == "GET": return render(request, 'arya/delete_view.html') # GET请求,到达确认页面 else: obj.delete() return redirect(self.reverse_list_url()) # POST请求,直接删除 class AryaSite(object): def __init__(self): self._registry = {} def register(self, class_name, config_class): """ if not class_name: class_name = ModelAdmin 没有这个判断,所以注册的时候必须传两个参数 注册方式一: 在app01的arya.py中如下方式注册(可以有多个app01这样的应用): v1.site.register(models.UserInfo,AryaConfig) v1.site.register(models.UserType,AryaConfig) 则: self._registry = { models.UserInfo: AryaConfig(models.UserInfo,site), models.UserType: AryaConfig(models.UserType,site), } 备注 函数中的self指的是对象本身, UserInfo对象 = AryaConfig(models.UserInfo,site) UserType对象 = AryaConfig(models.UserType,site) 注册方式二: 在app01的arya.py中如下方式注册(可以有多个app01这样的应用): class UserInfoConfig(v1.AryaConfig): ...... v1.site.register(models.UserInfo,UserInfoConfig) class UserTypeConfig(v1.AryaConfig): ...... v1.site.register(models.UserType,UserTypeConfig) 则: self._registry = { models.UserInfo: UserInfoConfig(models.UserInfo,site), models.UserType: UserTypeConfig(models.UserType,site), } 备注: 函数中的self指的是site UserInfo对象 = UserInfoConfig(models.UserInfo,site) UserType对象 = UserTypeConfig(models.UserType,site) :param class_name: :param config_class: :return: """ self._registry[class_name] = config_class(class_name, self) @property def urls(self): from django.conf.urls import url, include partterns = [ url(r'^login/', self.login), url(r'^logout/', self.logout), ] for model_class, arya_config_obj in self._registry.items(): # model_class 代表的是模块,比如UserInfo # arya_config_obj 代表的是本模块中的AryaConfig的对象或者被继承修改后的如UserInfoConfig的对象 app_model_name = r'^{0}/{1}/'.format( model_class._meta.app_label, model_class._meta.model_name) print(model_class._meta.app_label, model_class._meta.model_name) # /app01/userinfo/ # /app01/usertype/ # model_class._meta.app_label 代表model所在的模块名比如app01 # model_class._meta.model_name 代表model对应的表的小写名,比如userinfo pt = url(app_model_name, (arya_config_obj.urls, None, None)) # url这个函数的第二个参数是一个元组,元组的第一个元素是列表 # arya_config_obj.urls 即 # AryaConfig类或者UserInfoConfig类中的urls,此时self指的是这个对象!!!! partterns.append(pt) return partterns def login(self, request): from django.shortcuts import HttpResponse return HttpResponse('Login') def logout(self, request): from django.shortcuts import HttpResponse return HttpResponse('Logout') site = AryaSite()
templates/arya/include/form.html(被其他html模板include)
<form class="form-horizontal" method="POST" novalidate> {% csrf_token %} {% for item in form %} <div class="form-group col-sm-6" style="margin-bottom: 20px;"> <label for="inputEmail3" class="col-sm-2 control-label">{{ item.label }}</label> <div class="col-sm-10" style="position: relative"> <!-- <input type="email" class="form-control" id="inputEmail3" placeholder="Email"> --> {{ item }} <div style="position: absolute;">{{ item.errors.0 }}</div> </div> </div> {% endfor %} <div class="form-group"> <div class="col-sm-offset-1 col-sm-10"> <input type="submit" class="btn btn-primary" value="提交"> </div> </div> </form>
templates/arya/add_view.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/arya/plugins/bootstrap/css/bootstrap.css"/> <link rel="stylesheet" href="/static/arya/css/form-control.css"/> </head> <body> <div class="container"> <h1>添加数据</h1> {% include 'arya/include/form.html' %} </div> </body> </html>
templates/arya/change_view.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/arya/plugins/bootstrap/css/bootstrap.css"/> <link rel="stylesheet" href="/static/arya/css/form-control.css"/> </head> <body> <div class="container"> <h1>修改数据</h1> {% include 'arya/include/form.html' %} </div> </body> </html>
templates/arya/changelist.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/arya/plugins/bootstrap/css/bootstrap.css" /> </head> <body> <div class="container"> <h1>列表页面</h1> {% if cl.search_list %} <div> <form method='GET'> <input type="text" name="q" value="{{ cl.q_value }}" class="form-control" style="display: inline-block;width: 200px;" /> <input type="submit" value="搜索" class="btn btn-primary" /> </form> </div> {% endif %} <div style="margin: 10px 0"> {% if cl.show_add %} <a class="btn btn-primary" href="{{ cl.add_url }}">添加</a> {% endif %} </div> <form method="POST"> {% csrf_token %} {% if cl.actions %} <div style="margin: 10px 0"> <select class="form-control" style="width: 200px;display: inline-block" name="select_ac"> {% for item in cl.action_options %} <option value="{{ item.value }}">{{ item.text }}</option> {% endfor %} </select> <input type="submit" value="执行" class="btn btn-success" /> </div> {% endif %} <table class="table table-bordered table-hover"> <thead> <tr> {% for item in cl.table_header %} <th>{{ item }}</th> {% endfor %} </tr> </thead> <tbody> {% for row in cl.table_body %} <tr> {% for col in row %} <td>{{ col }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> <ul class="pagination"> {{ cl.page_html|safe }} </ul> </form> </div> </body> </html>
templates/arya/delete_view.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div class="container"> <h1>是否确定删除</h1> <form method="POST"> {% csrf_token %} <input type="submit" class="btn btn-danger" value="确定" /> </form> </div> </body> </html>
arya/utils/page.py
import urllib.parse class Pagination(object): def __init__(self, current_page, all_count, base_url, query_params, per_page=10, pager_page_count=11): """ 分页初始化 :param current_page: 当前页码 :param all_count: 数据库中总条数 :param base_url: http://127.0.0.1:8000/index.html/?page=17# 中的/index.html/ :param query_params: 【这个较之前的分页器多了这个参数:查询参数】 :param per_page: 每页显示数据条数 :param pager_page_count: 页面上最多显示的页码数量 """ self.base_url = base_url self.query_params = query_params # QueryDict """ { q:'xxx', page:2 } query_params[page] = 9 { q:'xxx', page:9 } QueryDict.urlencode() # /arya/app01/userinfo/?q=xxx&page=9 """ try: self.current_page = int(current_page) if self.current_page <= 0: raise Exception() except Exception as e: self.current_page = 1 self.per_page = per_page self.all_count = all_count self.pager_page_count = pager_page_count pager_count, b = divmod(all_count, per_page) if b != 0: pager_count += 1 self.pager_count = pager_count half_pager_page_count = int(pager_page_count / 2) self.half_pager_page_count = half_pager_page_count @property def start(self): """ 数据获取值起始索引 :return: """ return (self.current_page - 1) * self.per_page @property def end(self): """ 数据获取值结束索引 :return: """ return self.current_page * self.per_page def page_html(self): """ 生成HTML页码 :return: """ # 如果数据总页码pager_count<11 pager_page_count if self.pager_count < self.pager_page_count: pager_start = 1 pager_end = self.pager_count else: # 数据页码已经超过11 # 判断: 如果当前页 <= 5 half_pager_page_count if self.current_page <= self.half_pager_page_count: pager_start = 1 pager_end = self.pager_page_count else: # 如果: 当前页+5 > 总页码 if (self.current_page + self.half_pager_page_count) > self.pager_count: pager_end = self.pager_count pager_start = self.pager_count - self.pager_page_count + 1 else: pager_start = self.current_page - self.half_pager_page_count pager_end = self.current_page + self.half_pager_page_count page_list = [] if self.current_page <= 1: prev = '<li><a href="#">上一页</a></li>' else: self.query_params['page'] = self.current_page - 1 prev = '<li><a href="%s?%s">上一页</a></li>' % (self.base_url,self.query_params.urlencode()) page_list.append(prev) for i in range(pager_start, pager_end + 1): self.query_params['page'] = i if self.current_page == i: tpl = '<li class="active"><a href="%s?%s">%s</a></li>' % ( self.base_url, self.query_params.urlencode(), i,) else: tpl = '<li><a href="%s?%s">%s</a></li>' % (self.base_url, self.query_params.urlencode(), i,) page_list.append(tpl) if self.current_page >= self.pager_count: nex = '<li><a href="#">下一页</a></li>' else: self.query_params['page'] = self.current_page + 1 nex = '<li><a href="%s?%s">下一页</a></li>' % (self.base_url, self.query_params.urlencode(),) page_list.append(nex) page_str = "".join(page_list) return page_str
aray/apps.py(注册arya文件,这样会执行所有app下的arya.py文件)
from django.apps import AppConfig class AryaConfig(AppConfig): name = 'arya' def ready(self): from django.utils.module_loading import autodiscover_modules autodiscover_modules('arya')
源码地址:链接: https://pan.baidu.com/s/1qYME89I 密码: ese7
使用方法
备注:这个示例没有和rbac结合,后面的例子会介绍这种情况
1,创建Django项目CURD
2,创建业务app如cmdb
3,拷贝arya到CURD的目录下
4,setting.py中注册cmdb和arya,注册方式如下:
INSTALLED_APPS = [ 'django.contrib.admin', ......'arya.apps.AryaConfig', 'cmdb', ]
5,在cmdb的目录下创建arya.py文件,内容如下
from arya.service import v1 from . import models from django.forms import ModelForm class UserInfoModelForm(ModelForm): class Meta: model = models.Server # fields = "__all__" fields = ['host','port'] # exclude = ['name'] error_messages = { 'host': { 'required': 'host不能为空', }, 'port': { 'required': '密码不能为空', } } class ServerConfig(v1.AryaConfig): # 1. 列表显示列相关 list_display = ['host','port'] # 2. 添加按钮相关(AryaConfig中默认的是False) show_add = True # 3. ModelForm,如上定义了添加和修改的时候ModelForm只对host字段生效,且错误消息为'host不能为空' model_form_class = UserInfoModelForm # 4. 指定可以搜索哪几列,并指定host是模糊搜索,port是精确搜索 search_list = ['host__contains','port'] # 5.分页配置(AryaConfig中默认的是每页显示10个,最多显示11个页面,如果想单独设置应该也可以(子类配置优先)) # 6. Action v1.site.register(models.Server,ServerConfig)
6,urls.py
from django.conf.urls import url from django.contrib import admin from arya.service import v1 urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^arya/', (v1.site.urls,None,'arya')), ]
7,后续如果有新加的需要增删改成的类,直接重复第5步,写一个XxxConfig类,然后v1.site.register(models.Xxx,XxxConfig)即可
8,访问方式:http://ip:port/arya/appname/表名小写 ====》 到大changelist.html

浙公网安备 33010602011771号