##今日更新内容
#1、search_field 需要掌握技术点 Q查询 1.直接用Q去查 2. from app01 import models models.Book.objects.filter(title__contains='三',price__contains=2) <QuerySet []> from django.db.models import Q models.Book.objects.filter(Q(title__contains='三')|Q(price__contains=2)) <QuerySet [<Book: 三国演义>]> models.Book.objects.filter(Q(title__contains='三')|Q(price__contains=8)) <QuerySet [<Book: 红楼梦>, <Book: 三国演义>]> q = Q() q.children.append(('title__contains','三')) # 添加查询条件 q.children.append(('price__contains',8)) models.Book.objects.filter(q) <QuerySet [<Book: 三国演义>]> q.connector = 'or' # q对象默认也是and关系 但是可以通过connector修改成or的关系 models.Book.objects.filter(q) <QuerySet [<Book: 红楼梦>, <Book: 三国演义>]> #2、actions 实现批处理操作,当用户选中相对应的check框,选择相应的批处理操作(如:更新、删除等)进行统一操作 #3、list_filter 1.显示外键字段 及外键字段所对应的模型表中的所有的数据 获取外键字段所对应的模型表变量名 models.Book._meta.get_field('publish').rel.to 2.{'publish':[publish_obj,publish_obj1,]} 3.给数据对象简单的配置href链接 4.深拷贝request.GET 完成自动保存get携带的参数的功能 5.点击标签后 样式变换 6.all标签 7.后端还是利用q对象进行数据过滤 直接用默认的and关系 需要掌握技术点 #获取外键字段对应的表变量名,field是字段的字符串形式,该方法能根据他获取表名 rel_model = self.config_obj.model._meta.get_field(field).rel.to #4、pop功能:父子页面如何通信? doc操作创建option标签 需要解决的问题: 1、在添加操作页面在外键字段右边添加一个加号,那后端怎么判断哪一个字段是外键字段 解决方案: 循环模型表、拿到一个个对象,判断对象是否是,如果是,就给过滤的对象添加额外的属性,用于前端渲染的时候 根据是否存在这个额外添加的属性进行判断,判断通过就在外键字段后面添加+加号。 2、给加号绑定点击事件、当点击加号时要跳转到对应外键表的添加页面,那后端要动态传对应不同表的添加页面的url,之前 二级url是怎么拼接来着? 后端: # print(form_obj.name) #拿到外键字段publish 、authors rel_model = self.model._meta.get_field(form_obj.name).rel.to #通过字段名拿到所对应的模型表 rel_app_label = rel_model._meta.app_label #通过模型表拿到所对应的应用名 rel_model_name = rel_model._meta.model_name #通过模型表拿到所对应的模型表名 url = reverse('%s_%s_%s'%(rel_app_label,rel_model_name,'add')) form_obj.url = url #这里给对象添加属性,前端直接可以使用,这种方法牢记,解决前后端数据传递问题 3、如何区分你子页面添加数据还是正常窗口添加页面?怎么理解呢? 问题:当在添加书籍book页面,点击加号跳转小窗口到对应的authos页面或者出版社publish小窗口页面,添加完数据后,不能直接 返回的是author页面 而是自动关闭小窗口,继续进行book页面添加操作,而且选择下拉框默认选中你所创建的作者或者出版社 信息。 解决方案: 为了识别父页面子页面,在打开子页面的url后面加get请求参数,获取form_obj渲染的标签id值form_obj.auto_id,然后拼接到 get请求url后面,这样子页面添加请求时通过url就能识别,当时别子页面以后,要return render(request,'stark/pop.html',locals()) 在新子页面中要直接关闭子页面操作,再关闭之前还要调用父页面方法,不管是单标签还是多标签, 4、父页面要干什么?父页面需要自动渲染一个option标签 这里就学到了document创建option标签的方法,思考渲染标签需要什么数据?子页面pop.html怎么调用父页面add_view.html使用了 子页面可以调用父页面中的方法 window.opener.fatherFunc(...) window.close() 父页面创建option标签: function addOptions(pop_back_id,pk,text) { //动态创建option标签 想想创建标签需要什么参数,不过函数比较好写的原因是所需要什么参数 //先定义形参就可以,到时谁调用谁给我传过来 var optEle = document.createElement('option'); //给标签赋属性 optEle.innerText = text; optEle.value = pk; optEle.selected = 'selected';//默认选中 //查找option所在的父标签 var seEle = document.getElementById(pop_back_id); seEle.appendChild(optEle) }
##search_field:或查询条件
#自定义配置类中: class BookConfig(ModelStark): search_fields = ['title','price'] #自定义search_fields查询条件 且为or条件 #默认配置类中 class ModelStark(object): #ModelStark中时默认的参数,用户自定义的的在C:\starkpro\app01\stark.py list_display = ['__str__',] list_display_links = [] model_form_class = None search_fields = [] #默认search_fields def __init__(self,model): self.model = model #self.model是指拿到当前对象所对应的模型表名,即四张表对应都不一样 self.app_label = self.model._meta.app_label #直接给对象初始化应用名 self.model_name = self.model._meta.model_name #直接给对象初始化表名 self.key_word = '' #初始化 def list_view(self, request): #查看self.model <class 'app01.models.Book'> 那张表查看就代表谁 # print(self.model) queryset = self.model.objects.all() #search_file功能 key_word = request.GET.get('q') #接受前端传来的数据 #先对key_word初始值进行清空操作 self.key_word = '' if key_word: """ 需要解决问题: 1、变量名问题 前后端传递的是字符串,orm数据查询语句时需要的是字段 2、查询条件由and改为or(这里再说明一下django源码中默认admin五大参数中search_files是或查询条件) 解决方案:Q查询 Q查询有两种方法: 1、正常情况可以解决and 或者or 但是没法解决变量名问题 2、另一种用法 q = Q() q.children.append(('title__contains','三')) # 添加查询条件 q.children.append(('price__contains',8)) models.Book.objects.filter(q) <QuerySet [<Book: 三国演义>]> q.connector = 'or' # q对象默认也是and关系 但是可以通过connector修改成or的关系 models.Book.objects.filter(q) <QuerySet [<Book: 红楼梦>, <Book: 三国演义>]> """ self.key_word = key_word from django.db.models import Q q = Q() #创建q对象 q.connector = 'or' #指定q查询条件 #不停的往children中添加查询条件 for search_field in self.search_fields: #在自定义配置类中serch_fields = ['title','price'] print(search_field) q.children.append(('%s__icontains'%search_field,key_word)) #contains为包含 价格i忽略大小写 queryset = queryset.filter(q) #展示类调用 show_obj = ShowList(self,queryset,request) url = self.get_reverse_url('add') return render(request,'stark/list_view.html',locals()) #前端list_view.html {% extends 'stark/base.html' %} {% block content %} <h2 class="text-center">数据展示</h2> <div class="col-md-8 col-md-offset-2"> <a href="{{ url }}" class="btn btn-primary">添加数据</a> {% if show_obj.config_obj.search_fields %} <form class="form-inline pull-right"> <div class="form-group"> <div class="input-group"> <input type="text" class="form-control" id="exampleInputAmount" placeholder="关键字" name="q" value="{{ show_obj.config_obj.key_word }}"> </div> </div> <button type="submit" class="btn btn-primary">Search</button> </form> {% endif %} <table class="table table-striped table-bordered table-hover"> <thead> <tr> {% for foo in show_obj.get_header %} <td>{{ foo }}</td> {% endfor %} </tr> </thead> <tbody> {% for body in show_obj.get_body %} <tr> {% for foo in body %} <td> {{ foo }} </td> {% endfor %} </tr> {% endfor %} </tbody> </table> {{ show_obj.page_obj.page_html|safe }} </div> {% endblock %}
##actions批处理功能
#前端 list_view.html {% extends 'stark/base.html' %} {% block content %} <h2 class="text-center">数据展示</h2> <div class="col-md-8 col-md-offset-2"> <a href="{{ url }}" class="btn btn-primary">添加数据</a> {% if show_obj.config_obj.search_fields %} <form class="form-inline pull-right"> <div class="form-group"> <div class="input-group"> <input type="text" class="form-control" id="exampleInputAmount" placeholder="关键字" name="q" value="{{ show_obj.config_obj.key_word }}"> </div> </div> <button type="submit" class="btn btn-primary">Search</button> </form> {% endif %} <form action="" method="post" class="form-inline"> {% csrf_token %} <select name="action" id="" class="form-control"> <option value="">--------------------------</option> {% for foo in show_obj.get_actions %} <option value="{{ foo.name }}">{{ foo.desc }}</option> {% endfor %} </select> <input type="submit" value="GO" class="btn btn-danger"> <table class="table table-striped table-bordered table-hover"> <thead> <tr> {% for foo in show_obj.get_header %} <td>{{ foo }}</td> {% endfor %} </tr> </thead> <tbody> {% for body in show_obj.get_body %} <tr> {% for foo in body %} <td> {{ foo }} </td> {% endfor %} </tr> {% endfor %} </tbody> </table> </form> {{ show_obj.page_obj.page_html|safe }} </div> {% endblock %} #自定义配置类C:\starkpro\app01\stark.py class BookConfig(ModelStark): def patch_init(self,request,queryset): queryset.update(price=888) patch_init.desc = '价格批量处理' def patch_delete(self,request,queryset): queryset.delete() patch_delete.desc = '价格批量删除' actions = [patch_init,patch_delete] #默认配置类 class ModelStark(object): #ModelStark中时默认的参数,用户自定义的的在C:\starkpro\app01\stark.py list_display = ['__str__',] list_display_links = [] model_form_class = None search_fields = [] actions = [] #添加一个默认action def check_box(self,is_header=False,obj=None): if is_header: return '选择' #添加每一个check的id值,以便用户选中后后台需要获取 return mark_safe('<input type="checkbox" value="%s" name="selected_action"/>'%obj.pk) def list_view(self, request): #查看self.model <class 'app01.models.Book'> 那张表查看就代表谁 # print(self.model) if request.method == 'POST': #获取用户选中的函数字符串名 action = request.POST.get('action') #获取用户选中的逐渐字段 pk_list = request.POST.getlist('selected_action') #根据主键字段查询所有的数据 queryset_list = self.model.objects.filter(pk__in=pk_list) #通过反射由函数字符串找函数名 real_action = getattr(self,action) #这里self是指用户自定义的self #将queryset对象传给函数处理 real_action(request,queryset_list) queryset = self.model.objects.all() queryset = self.search(queryset,request) #展示类调用 show_obj = ShowList(self,queryset,request) url = self.get_reverse_url('add') return render(request,'stark/list_view.html',locals()) #展示类 class ShowList: def get_actions(self): tmp_list = [] #actions = [patch_init] for action in self.config_obj.actions: #循环用户自定义ations列表 tmp_list.append({ 'name':action.__name__,#字符串对应的名字 'desc':action.desc }) return tmp_list #[{'name':'','desc':''}]
##filter前端渲染和筛选功能
#自定义配置类 class BookConfig(ModelStark): list_filter = ['publish','authors'] #默认配置类 class ModelStark(object): list_filter=[] def list_view(self, request): #查看self.model <class 'app01.models.Book'> 那张表查看就代表谁 # print(self.model) if request.method == 'POST': #获取用户选中的函数字符串名 action = request.POST.get('action') #获取用户选中的逐渐字段 pk_list = request.POST.getlist('selected_action') #根据主键字段查询所有的数据 queryset_list = self.model.objects.filter(pk__in=pk_list) #通过反射由函数字符串找函数名 real_action = getattr(self,action) #这里self是指用户自定义的self #将queryset对象传给函数处理 real_action(request,queryset_list) queryset = self.model.objects.all() queryset = self.search(queryset,request) #filter功能 list_filter=['publish','authors'] q = Q() for field in self.list_filter: if field in request.GET: filter_value = request.GET.get(field) q.children.append((field,filter_value)) queryset = queryset.filter(q) #展示类调用 show_obj = ShowList(self,queryset,request) url = self.get_reverse_url('add') return render(request,'stark/list_view.html',locals()) #展示类 class ShowList: def get_filter(self): tmp_dict = {} for field in self.config_obj.list_filter: #用户自定配置数据格式为list_filter = ['publishs','authors'] tmp_list = [] #获取外键字段对应的表变量名,field是字段的字符串形式,该方法能根据他获取表名 rel_model = self.config_obj.model._meta.get_field(field).rel.to rel_queryset = rel_model.objects.all() filter_value = self.request.GET.get(field) import copy """ 渲染前端ALL标签 点击ALL 标签,使当前所在的字段从访问网址中删除掉 """ params1 = copy.deepcopy(self.request.GET) if field in params1: params1.pop(field) s = mark_safe("<a href='?%s'>ALL</a>"%params1.urlencode()) else: s=mark_safe("<a href=''>ALL</a>") tmp_list.append(s) """ 下面渲染每一个表对象下的字段 """ params = copy.deepcopy(self.request.GET) for obj in rel_queryset: params[field] = obj.pk #将每一个对象对应的id存到字典中 if filter_value == str(obj.pk): #如果该标签被点击了,为了显示为红色,利用条件来添加一个action类属性 s = mark_safe('<a href="?%s" class="active">%s</a>' % (params.urlencode(), str(obj))) else: #params.urlencode() 将存入的对象以?publish=1&authors=1方式读出来,即前端访问网址能保存搜索条件了 s = mark_safe('<a href="?%s">%s</a>'%(params.urlencode(),str(obj))) tmp_list.append(s) tmp_dict[field] = tmp_list #{'publishs':[obj1,obj2],'authors':[obj1,obj2]} return tmp_dict #前端list_view.html {% extends 'stark/base.html' %} {% block content %} <h2 class="text-center">数据展示</h2> <div class="col-md-9 "> <a href="{{ url }}" class="btn btn-primary">添加数据</a> {% if show_obj.config_obj.search_fields %} <form class="form-inline pull-right"> <div class="form-group"> <div class="input-group"> <input type="text" class="form-control" id="exampleInputAmount" placeholder="关键字" name="q" value="{{ show_obj.config_obj.key_word }}"> </div> </div> <button type="submit" class="btn btn-primary">Search</button> </form> {% endif %} <form action="" method="post" class="form-inline"> {% csrf_token %} <select name="action" id="" class="form-control"> <option value="">--------------------------</option> {% for foo in show_obj.get_actions %} <option value="{{ foo.name }}">{{ foo.desc }}</option> {% endfor %} </select> <input type="submit" value="GO" class="btn btn-danger"> <table class="table table-striped table-bordered table-hover"> <thead> <tr> {% for foo in show_obj.get_header %} <td>{{ foo }}</td> {% endfor %} </tr> </thead> <tbody> {% for body in show_obj.get_body %} <tr> {% for foo in body %} <td> {{ foo }} </td> {% endfor %} </tr> {% endfor %} </tbody> </table> </form> {{ show_obj.page_obj.page_html|safe }} </div> <div class="col-md-3"> {% if show_obj.config_obj.list_filter %} <div class="alert-info text-center">FILTER</div> {% for k,v in show_obj.get_filter.items %} <div class="panel panel-default"> <div class="panel-heading">By {{ k }}</div> <div class="panel-body"> {% for foo in v %} <p>{{ foo }}</p> {% endfor %} </div> </div> {% endfor %} {% endif %} </div> {% endblock %}
##pop功能:父子页面如何通信?怎么定义自动创建option标签函数?
#默认配置类 class ModelStark(object): def add_view(self, request): model_form_class = self.get_model_form() model_form_obj = model_form_class() if request.method == 'POST': model_form_obj = model_form_class(request.POST) pop_back_id = request.GET.get('pop_back_id') if model_form_obj.is_valid(): obj = model_form_obj.save() #保存以后能拿到一个对象 if pop_back_id: #如果pop_back_id有值 说明是子页面提交过来的post请求 #给子页面传创建option标签所需要的参数 pk = obj.pk text = str(obj) return render(request,'stark/pop.html',locals()) #如果是子页面 渲染一个新页面 return redirect(self.get_reverse_url('list')) #渲染外键字段后面添加加号 from django.forms.models import ModelChoiceField for form_obj in model_form_obj: if isinstance(form_obj.field,ModelChoiceField): form_obj.is_pop = True # print(form_obj.name) #拿到外键字段publish 、authors rel_model = self.model._meta.get_field(form_obj.name).rel.to #通过字段名拿到所对应的模型表 rel_app_label = rel_model._meta.app_label #通过模型表拿到所对应的应用名 rel_model_name = rel_model._meta.model_name #通过模型表拿到所对应的模型表名 url = reverse('%s_%s_%s'%(rel_app_label,rel_model_name,'add')) # print(form_obj.auto_id) #拿到当前 input渲染的id值 id_publish、id_authors url = url +'?pop_back_id=%s'%form_obj.auto_id form_obj.url = url return render(request, 'stark/add_view.html', locals()) #前端:add_view.html 渲染外键添加加号 和绑定点击事件跳出小窗口 和 定义自动创建option标签函数 {% extends 'stark/base.html' %} {% block css %} <link rel="stylesheet" href="/static/css/my_css.css"> {% endblock %} {% block content %} <div class="col-md-6 col-md-offset-3"> <h2 class="text-center">添加数据</h2> <form action="" method="post"> {% csrf_token %} {% for form_obj in model_form_obj %} <div class="plus-father"> <p>{{ form_obj.label }}{{ form_obj }} <span>{{ form_obj.error.0 }}</span> </p> <div> {% if form_obj.is_pop %} <span class="plus" onclick="WindowOpen('{{ form_obj.url }}')">+</span> {% endif %} </div> </div> {% endfor %} <input type="submit" class="btn btn-success pull-right"> </form> </div> <script> //绑定点击函数, window.open跳出子页面,url为动态数据,应该怎么获取这个是个难点 function WindowOpen(url){ window.open(url,'','width=800px,height=400px') } function addOptions(pop_back_id,pk,text) { //动态创建option标签 想想创建标签需要什么参数,不过函数比较好写的原因是所需要什么参数 //先定义形参就可以,到时谁调用谁给我传过来 var optEle = document.createElement('option'); //给标签赋属性 optEle.innerText = text; optEle.value = pk; optEle.selected = 'selected';//默认选中 //查找option所在的父标签 var seEle = document.getElementById(pop_back_id); seEle.appendChild(optEle) } </script> {% endblock %} #前端:base.html 使用相对绝对位置调节加号位置 <style> table{ margin-top: 10px; } .active{ color: red; } .plus-father{ position: relative; } .plus{ font-size: 24px; color: #369; position: absolute; right: -20px; top: 20px; } </style> #前端:pop.html 关闭子页面 和 调用父页面自动创建option函数 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link rel="stylesheet" href="/static/bs-3.3.7/css/bootstrap.css"> <script src="/static/bs-3.3.7/js/bootstrap.min.js"></script> </head> <body> <script> //调用父页面add_view.html函数,为父页面自动创建option标签,创建该标签所需要的参数,从后端拿,想想都需要哪些参数 //这些参数从后端该怎么拿 window.opener.addOptions('{{ pop_back_id }}','{{ pk }}','{{ text }}'); window.close() //为父页面渲染option标签后,主动关闭子页面 </script> </body> </html>