10 star组件之分页, search模糊查询, action批量处理
1、分页组件高阶
1、分页的class形式(有bug,请看下面的)
""" 自定义分页组件 """ class Pagination(object): # def __init__(self, data_num, current_page, url_prefix, params, per_page=10, max_show=3): def __init__(self, data_num, current_page, url_prefix,per_page=10, max_show=3): """ 进行初始化. :param data_num: 数据总数 :param current_page: 当前页 :param url_prefix: 生成的页码的链接前缀 :param per_page: 每页显示多少条数据 :param max_show: 页面最多显示多少个页码 """ self.data_num = data_num self.per_page = per_page self.max_show = max_show self.url_prefix = url_prefix # 把页码数算出来 self.page_num, more = divmod(data_num, per_page) if more: self.page_num += 1 try: self.current_page = int(current_page) except Exception as e: self.current_page = 1 # 如果URL传过来的页码数是负数 if self.current_page <= 0: self.current_page = 1 # 如果URL传过来的页码数超过了最大页码数 elif self.current_page > self.page_num: self.current_page = self.page_num # 默认展示最后一页 # 页码数的一半 算出来 self.half_show = max_show // 2 # 页码最左边显示多少 if self.current_page - self.half_show <= 1: self.page_start = 1 self.page_end = self.max_show elif self.current_page + self.half_show >= self.page_num: # 如果右边越界 self.page_end = self.page_num self.page_start = self.page_num - self.max_show else: self.page_start = self.current_page - self.half_show # 页码最右边显示 self.page_end = self.current_page + self.half_show # import copy # self.params = copy.deepcopy(params) # {"page":"12","title_startwith":"py","id__gt":"5"} @property def start(self): # 数据从哪儿开始切 return (self.current_page - 1) * self.per_page @property def end(self): # 数据切片切到哪儿 return self.current_page * self.per_page def page_html(self): # 生成页码 l = [] # 加一个首页 l.append('<li><a href="{}?page=1">首页</a></li>'.format(self.url_prefix)) # 加一个上一页 if self.current_page == 1: l.append('<li class="disabled" ><a href="#">«</a></li>'.format(self.current_page)) else: l.append('<li><a href="{}?page={}">«</a></li>'.format(self.url_prefix, self.current_page - 1)) # {"page":"12","title_startwith":"py","id__gt":"5"} # "page=12&title_startwith=py&id__gt=5" # print(self.params.urlencode()) for i in range(self.page_start, self.page_end + 1): # self.params["page"] = i # {"page":"7","title_startwith":"py","id__gt":"5"} # "page=7&title_startwith=py&id__gt=5" if i == self.current_page: tmp = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i) else: # tmp = '<li><a href="{0}?{1}">{2}</a></li>'.format(self.url_prefix, self.params.urlencode(), i) tmp = '<li><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i) l.append(tmp) # 加一个下一页 if self.current_page == self.page_num: l.append('<li class="disabled"><a href="#">»</a></li>'.format(self.current_page)) else: l.append('<li><a href="{}?page={}">»</a></li>'.format(self.url_prefix, self.current_page + 1)) # 加一个尾页 l.append('<li><a href="{}?page={}">尾页</a></li>'.format(self.url_prefix, self.page_num)) return "".join(l)
from django.shortcuts import render,HttpResponse # Create your views here. from .models import * def index(request): ''' # 生成假数据 book_list=[] for i in range(500): book_obj=Book(title="book_%s"%i,price=i*i) book_list.append(book_obj) Book.objects.bulk_create(book_list) ''' base_url = request.path # /index/ # 当前url路径 current_page=request.GET.get("page",1) # 获取当前url中的page all_count=Book.objects.all().count() # 所有book数据多少条 # 分页器 from app01.utils.page import Pagination pagination=Pagination(all_count,int(current_page),base_url,per_page=10, max_show=11) # pagination=Pagination(all_count,int(current_page),base_url,request.GET,per_page=10, max_show=11) # 所有数据条数,当前页的page=3,当前url路径,request.GET请求,每页显示数据,分页器最大展示几个项目 print(pagination.start) print(pagination.end) book_list =Book.objects.all()[pagination.start:pagination.end] # 对数据进行切片 from django.http.request import QueryDict # dic = QueryDict(mutable=True) # dic["info"] = 123 # print(type(request.GET)) # request.GET["info"]=123 import copy params=copy.deepcopy(request.GET) params["xxx"]=123 return render(request,"index.html",locals())
from django.db import models # Create your models here. class Book(models.Model): title=models.CharField(max_length=32) price=models.DecimalField(max_digits=8,decimal_places=2) def __str__(self): return self.title
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <ul> {% for foo in book_list %} <li>{{ foo }}</li> {% endfor %} </ul> <nav> <ul class="pagination"> {{ pagination.page_html|safe }} </ul> </nav> </body> </html>
2、如何扩展分页
2、整合展示数据showlist类
def list_view(self, request): print(self.model) # <class 'app01.models.Book'> 用户访问的模型表 # 构建表头 header_list = [] # # header_list = ['选择','pk',...'操作','操作'] for field in self.new_list_play(): if callable(field): # header_list.append(field.__name__) val = field(self,header=True) header_list.append(val) else: if field == "__str__": header_list.append(self.model._meta.model_name.upper()) else: val = self.model._meta.get_field(field).verbose_name # 中文名称 header_list.append(val) # 构建表单 data_list = self.model.objects.all() # [obj1,obj2,...] new_data_list = [] for obj in data_list: # Book表模型,Author表模型 temp = [] for field in self.new_list_play(): # ['name','age'] if callable(field): # edit() 可调用的 val = field(self,obj) # 直接调用edit()函数 print('val--------->',val) else: val = getattr(obj,field) # 反射 obj是实例对象,name是方法 # list_display_links 按钮 if field in self.list_display_links: model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) # print(_url) val = mark_safe("<a href='%s'>%s</a>"%(_url,field)) temp.append(val) new_data_list.append(temp) print('new_data_list',new_data_list) # 构造数据 [['jack', 44], ['mark', 33]] # 构建一个addurl add_url = self.get_add_url() return render(request,'list_view.html', locals())
showlist类
def list_view(self, request): # print(self.model) # <class 'app01.models.Book'> 用户访问的模型表 data_list = self.model.objects.all() # [obj1,obj2,...] # 构建表头,表单 show_list = ShowList(self,data_list) # self=ModelSTark实例对象 # 构建一个addurl add_url = self.get_add_url() return render(request,'list_view.html', locals())
class ShowList(object): def __init__(self,config, data_list): self.config = config # MOdelStark实例对象 self.data_list = data_list # 数据 def get_header(self): # 构建表头 header_list = [] # # header_list = ['选择','pk',...'操作','操作'] for field in self.config.new_list_play(): if callable(field): # header_list.append(field.__name__) val = field(self.config,header=True) header_list.append(val) else: if field == "__str__": header_list.append(self.config.model._meta.model_name.upper()) else: val = self.config.model._meta.get_field(field).verbose_name # 中文名称 header_list.append(val) return header_list def get_body(self): # 构建表单 new_data_list = [] for obj in self.data_list: # Book表模型,Author表模型 temp = [] for field in self.config.new_list_play(): # ['name','age'] if callable(field): # edit() 可调用的 val = field(self.config,obj) # 直接调用edit()函数 print('val--------->',val) else: val = getattr(obj,field) # 反射 obj是实例对象,name是方法 # list_display_links 按钮 if field in self.config.list_display_links: model_name = self.config.model._meta.model_name app_label = self.config.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) # print(_url) val = mark_safe("<a href='%s'>%s</a>"%(_url,field)) temp.append(val) new_data_list.append(temp) print('new_data_list',new_data_list) # 构造数据 [['jack', 44], ['mark', 33]] return new_data_list
3、stark组件之分页
stark/service/stark.py
# -*- coding: utf-8 -*- # @Time : 2018/08/17 0017 14:46 # @Author : Venicid from django.conf.urls import url from django.shortcuts import HttpResponse,render,redirect from django.utils.safestring import mark_safe from django.urls import reverse from stark.utils.page import Pagination class ShowList(object): def __init__(self,config, data_list,request): self.config = config # MOdelStark实例对象 self.data_list = data_list # 数据 self.request =request # 分页 data_count = self.data_list.count() current_page = int(self.request.GET.get('page',1)) base_path = self.request.path self.pagination = Pagination(current_page,data_count,base_path,self.request.GET,per_page_num=1, pager_count=11,) # 分页后的数据 self.page_data = self.data_list[self.pagination.start:self.pagination.end] def get_header(self): # 构建表头 header_list = [] # # header_list = ['选择','pk',...'操作','操作'] for field in self.config.new_list_play(): if callable(field): # header_list.append(field.__name__) val = field(self.config,header=True) header_list.append(val) else: if field == "__str__": header_list.append(self.config.model._meta.model_name.upper()) else: val = self.config.model._meta.get_field(field).verbose_name # 中文名称 header_list.append(val) return header_list def get_body(self): # 构建表单 new_data_list = [] for obj in self.page_data: #分页后的数据 # Book表模型,Author表模型 temp = [] for field in self.config.new_list_play(): # ['name','age'] if callable(field): # edit() 可调用的 val = field(self.config,obj) # 直接调用edit()函数 print('val--------->',val) else: val = getattr(obj,field) # 反射 obj是实例对象,name是方法 # list_display_links 按钮 if field in self.config.list_display_links: model_name = self.config.model._meta.model_name app_label = self.config.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) # print(_url) val = mark_safe("<a href='%s'>%s</a>"%(_url,field)) temp.append(val) new_data_list.append(temp) print('new_data_list',new_data_list) # 构造数据 [['jack', 44], ['mark', 33]] return new_data_list class ModelStark(object): list_display = ["__str__"] # 子类中没有,直接用父类自己的 list_display_links = [] modelform_class = [] def __init__(self,model, site): self.model = model self.site = site # 增删改查url def get_add_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_add" %(app_label,model_name)) return _url def get_list_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_list" %(app_label,model_name)) return _url # 复选框,编辑,删除 def checkbox(self,obj=None, header=False): if header: return mark_safe("<input id='choice' type='checkbox'>") return mark_safe("<input class='choice_item' type='checkbox'>") def edit(self,obj=None, header=False): if header: return "操作" # 方案1:固定url # return mark_safe("<a href=/stark/app01/userinfo/%s/change>编辑</a>") # 方案2:拼接url # return mark_safe("<a href='%s/change'>编辑</a>") # 方案3:反向解析 model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change"%(app_label,model_name),args=(obj.pk,)) # print("_url",_url) return mark_safe("<a href='%s'>编辑</a>"%_url) def deletes(self,obj=None, header=False): if header: return "操作" model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_delete"%(app_label,model_name),args=(obj.pk,)) return mark_safe("<a href='%s'>删除</a>"%_url) # ModelForm组件渲染 list、增、删、改页面 def get_modelform_class(self): """ModelForm组件""" if not self.modelform_class: from django.forms import ModelForm class ModelFormDemo(ModelForm): class Meta: model = self.model fields = "__all__" return ModelFormDemo else: return self.modelform_class def new_list_play(self): """构建 ['checkbox','pk', 'name', 'age', edit,'delete']""" temp = [] temp.append(ModelStark.checkbox) temp.extend(self.list_display) if not self.list_display_links: temp.append(ModelStark.edit) temp.append(ModelStark.deletes) return temp def list_view(self, request): # print(self.model) # <class 'app01.models.Book'> 用户访问的模型表 data_list = self.model.objects.all() # [obj1,obj2,...] # 构建表头,表单 show_list = ShowList(self,data_list,request) # self=ModelSTark实例对象 # 构建一个addurl add_url = self.get_add_url() return render(request,'list_view.html', locals()) def add_view(self, request): ModelFormDemo=self.get_modelform_class() form = ModelFormDemo() if request.method == "POST": form = ModelFormDemo(request.POST) if form.is_valid(): form.save() return redirect(self.get_list_url()) return render(request, "add_view.html",locals()) def delete_view(self, request, id): url = self.get_list_url() if request.method == "POST": self.model.objects.filter(pk=id).delete() return redirect(url) return render(request, "delete_view.html", locals()) def change_view(self, request, id): edit_obj = self.model.objects.filter(pk=id).first() ModelFormDemo=self.get_modelform_class() form = ModelFormDemo(instance=edit_obj) if request.method == "POST": form = ModelFormDemo(request.POST,instance=edit_obj) if form.is_valid(): form.save() return redirect(self.get_list_url()) return render(request, "change_view.html",locals()) #构造 add/delete/change def get_urls2(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label temp = [] temp.append(url(r'^$', self.list_view, name='%s_%s_list'%(app_label,model_name))) temp.append(url(r'^add/', self.add_view, name='%s_%s_add'%(app_label,model_name))) temp.append(url(r'^(\d+)/delete/', self.delete_view, name='%s_%s_delete'%(app_label,model_name))) temp.append(url(r'^(\d+)/change/', self.change_view, name='%s_%s_change'%(app_label,model_name))) return temp @property def urls2(self): return self.get_urls2(), None, None class StarkSite(object): """site单例类""" def __init__(self): self._registry = {} def register(self,model, stark_class=None): """注册""" if not stark_class: stark_class = ModelStark self._registry[model] = stark_class(model,self) def get_urls(self): """构造一层urls app01/book""" temp = [] for model, stark_class_obj in self._registry.items(): print(model, 'stark_clas_obj', stark_class_obj) # 不同的model模型表 """ <class 'app01.models.UserInfo'> ----> <app01.starkadmin.UserConfig object at 0x00000072DDB65198> <class 'app01.models.Book'> ----> <stark.service.stark.ModelStark object at 0x00000072DDB65240> """ app_label = model._meta.app_label # app01 model_name = model._meta.model_name # book # temp.append(url(r'^%s/%s'%(app_label, model_name),([],None,None))) temp.append(url(r'^%s/%s/'%(app_label, model_name),stark_class_obj.urls2)) """ path('app01/userinfo/',UserConfig(Userinfo,site).urls2), path('app01/book/',ModelStark(Book,site).urls2), """ return temp @property def urls(self): # return [],None,None return self.get_urls(),None,None site = StarkSite() # 单例对象
stark/utils/page.py(自定义分页,老师版本)
""" 自定义分页组件 """ class Pagination(object): def __init__(self, current_page, all_count, base_url,params, per_page_num=8, pager_count=11, ): """ 封装分页相关数据 :param current_page: 当前页 :param all_count: 数据库中的数据总条数 :param per_page_num: 每页显示的数据条数 :param base_url: 分页中显示的URL前缀 :param pager_count: 最多显示的页码个数 """ try: current_page = int(current_page) except Exception as e: current_page = 1 if current_page < 1: current_page = 1 self.current_page = current_page self.all_count = all_count self.per_page_num = per_page_num self.base_url = base_url # 总页码 all_pager, tmp = divmod(all_count, per_page_num) if tmp: all_pager += 1 self.all_pager = all_pager self.pager_count = pager_count # 最多显示页码数 self.pager_count_half = int((pager_count - 1) / 2) import copy params = copy.deepcopy(params) params._mutable = True self.params = params # self.params : {"page":77,"title":"python","nid":1} @property def start(self): return (self.current_page - 1) * self.per_page_num @property def end(self): return self.current_page * self.per_page_num def page_html(self): # 如果总页码 < 11个: if self.all_pager <= self.pager_count: pager_start = 1 pager_end = self.all_pager + 1 # 总页码 > 11 else: # 当前页如果<=页面上最多显示(11-1)/2个页码 if self.current_page <= self.pager_count_half: pager_start = 1 pager_end = self.pager_count + 1 # 当前页大于5 else: # 页码翻到最后 if (self.current_page + self.pager_count_half) > self.all_pager: pager_start = self.all_pager - self.pager_count + 1 pager_end = self.all_pager + 1 else: pager_start = self.current_page - self.pager_count_half pager_end = self.current_page + self.pager_count_half + 1 page_html_list = [] self.params["page"] = 1 first_page = '<li><a href="%s?%s">首页</a></li>' % (self.base_url, self.params.urlencode(),) page_html_list.append(first_page) if self.current_page <= 1: prev_page = '<li class="disabled"><a href="#">上一页</a></li>' else: self.params["page"] = self.current_page - 1 prev_page = '<li><a href="%s?%s">上一页</a></li>' % (self.base_url, self.params.urlencode(),) page_html_list.append(prev_page) for i in range(pager_start, pager_end): # self.params : {"page":77,"title":"python","nid":1} self.params["page"] = i # {"page":72,"title":"python","nid":1} if i == self.current_page: temp = '<li class="active"><a href="%s?%s">%s</a></li>' % (self.base_url, self.params.urlencode(), i,) else: temp = '<li><a href="%s?%s">%s</a></li>' % (self.base_url, self.params.urlencode(), i,) page_html_list.append(temp) if self.current_page >= self.all_pager: next_page = '<li class="disabled"><a href="#">下一页</a></li>' else: self.params["page"] = self.current_page + 1 next_page = '<li><a href="%s?%s">下一页</a></li>' % (self.base_url, self.params.urlencode(),) page_html_list.append(next_page) self.params["page"] = self.all_pager last_page = '<li><a href="%s?%s">尾页</a></li>' % (self.base_url, self.params.urlencode(),) page_html_list.append(last_page) return ''.join(page_html_list)
list_view.html
{% extends 'base.html' %} {% block title %} <title>list页面</title> {% endblock %} {% block header %} <h3>list页面</h3> {% endblock %} {% block content %} <a class="btn btn-primary" href="{{ add_url }}">添加数据</a> <table class="table table-bordered table-striped"> <tr> {% for header in show_list.get_header %} {# {% for header in header_list %}#} <th>{{ header }}</th> {% endfor %} </tr> {% for data in show_list.get_body %} {# {% for data in new_data_list %}#} <tr> {% for item in data %} <td>{{ item }}</td> {% endfor %} </tr> {% endfor %} </table> <nav> <ul class="pagination"> {{ show_list.pagination.page_html|safe }} </ul> </nav> {% endblock %} {% block javascript %} <script type="text/javascript"> $('#choice').click(function () { if ($(this).prop('checked')) { //对象自身属性中是否具有指定的属性 $('.choice_item').prop("checked", true) } else { $('.choice_item').prop("checked", false) } }) </script> {% endblock %}
3、stark组件之search模糊查询
1、orm中的模糊查询
2、orm中的Q查询 与或非
3、stark组件之模糊查询
def list_view(self, request): # print(self.model) # <class 'app01.models.Book'> 用户访问的模型表 # 模糊查询过滤 key_word = request.GET.get("q") from django.db.models import Q # 与或非 search_connection = Q() if key_word: search_connection.connector = "or" for search_field in self.search_fields: search_connection.children.append((search_field+"__contains", key_word)) data_list = self.model.objects.all().filter(search_connection) #按照showlist展示页面, 构建表头,表单 show_list = ShowList(self,data_list,request) # self=ModelSTark实例对象 # 构建一个查看addurl add_url = self.get_add_url() return render(request,'list_view.html', locals())
4、解耦
如果没有在starkadmin定义search_fields字段,就不显示search按钮
6、代码
# -*- coding: utf-8 -*- # @Time : 2018/08/17 0017 14:46 # @Author : Venicid from django.conf.urls import url from django.shortcuts import HttpResponse,render,redirect from django.utils.safestring import mark_safe from django.urls import reverse from stark.utils.page import Pagination class ShowList(object): def __init__(self,config, data_list,request): self.config = config # MOdelStark实例对象 self.data_list = data_list # 数据 self.request =request # 分页 data_count = self.data_list.count() current_page = int(self.request.GET.get('page',1)) base_path = self.request.path self.pagination = Pagination(current_page,data_count,base_path,self.request.GET,per_page_num=11, pager_count=11,) # 分页后的数据 self.page_data = self.data_list[self.pagination.start:self.pagination.end] def get_header(self): # 构建表头 header_list = [] # # header_list = ['选择','pk',...'操作','操作'] for field in self.config.new_list_play(): if callable(field): # header_list.append(field.__name__) val = field(self.config,header=True) header_list.append(val) else: if field == "__str__": header_list.append(self.config.model._meta.model_name.upper()) else: val = self.config.model._meta.get_field(field).verbose_name # 中文名称 header_list.append(val) return header_list def get_body(self): # 构建表单 new_data_list = [] for obj in self.page_data: #分页后的数据 # Book表模型,Author表模型 temp = [] for field in self.config.new_list_play(): # ['name','age'] if callable(field): # edit() 可调用的 val = field(self.config,obj) # 直接调用edit()函数 print('val--------->',val) else: val = getattr(obj,field) # 反射 obj是实例对象,name是方法 # list_display_links 按钮 if field in self.config.list_display_links: model_name = self.config.model._meta.model_name app_label = self.config.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) # print(_url) val = mark_safe("<a href='%s'>%s</a>"%(_url,field)) temp.append(val) new_data_list.append(temp) print('new_data_list',new_data_list) # 构造数据 [['jack', 44], ['mark', 33]] return new_data_list class ModelStark(object): list_display = ["__str__"] # 子类中没有,直接用父类自己的 list_display_links = [] modelform_class = [] search_fields = [] # 模糊查询字段 def __init__(self,model, site): self.model = model self.site = site # 增删改查url def get_add_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_add" %(app_label,model_name)) return _url def get_list_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_list" %(app_label,model_name)) return _url # 复选框,编辑,删除 def checkbox(self,obj=None, header=False): if header: return mark_safe("<input id='choice' type='checkbox'>") return mark_safe("<input class='choice_item' type='checkbox'>") def edit(self,obj=None, header=False): if header: return "操作" # 方案1:固定url # return mark_safe("<a href=/stark/app01/userinfo/%s/change>编辑</a>") # 方案2:拼接url # return mark_safe("<a href='%s/change'>编辑</a>") # 方案3:反向解析 model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change"%(app_label,model_name),args=(obj.pk,)) # print("_url",_url) return mark_safe("<a href='%s'>编辑</a>"%_url) def deletes(self,obj=None, header=False): if header: return "操作" model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_delete"%(app_label,model_name),args=(obj.pk,)) return mark_safe("<a href='%s'>删除</a>"%_url) # ModelForm组件渲染 list、增、删、改页面 def get_modelform_class(self): """ModelForm组件""" if not self.modelform_class: from django.forms import ModelForm class ModelFormDemo(ModelForm): class Meta: model = self.model fields = "__all__" return ModelFormDemo else: return self.modelform_class def new_list_play(self): """构建 ['checkbox','pk', 'name', 'age', edit,'delete']""" temp = [] temp.append(ModelStark.checkbox) temp.extend(self.list_display) if not self.list_display_links: temp.append(ModelStark.edit) temp.append(ModelStark.deletes) return temp ''' def list_view(self,request): ret1 = self.model.objects.filter(title__startswith='py') ret2 = self.model.objects.filter(price__in=[11,22,33,44,55]) ret3 = self.model.objects.filter(price__range=[10,20]) ret4 = self.model.objects.filter(title__contains='O') ret5 = self.model.objects.filter(title__icontains='O') return HttpResponse("过滤成功") ''' def get_search_condition(self,request): """search模糊查询""" key_word = request.GET.get("q",'') self.key_word = key_word from django.db.models import Q # 与或非 search_connection = Q() if key_word: search_connection.connector = "or" for search_field in self.search_fields: search_connection.children.append((search_field+"__contains", key_word)) return search_connection def list_view(self, request): # 获取search的Q对象 search_connection = self.get_search_condition(request) # 筛选获取当前表所有数据 data_list = self.model.objects.all().filter(search_connection) #按照showlist展示页面, 构建表头,表单 show_list = ShowList(self,data_list,request) # self=ModelSTark实例对象 # 构建一个查看addurl add_url = self.get_add_url() return render(request,'list_view.html', locals()) def add_view(self, request): ModelFormDemo=self.get_modelform_class() form = ModelFormDemo() if request.method == "POST": form = ModelFormDemo(request.POST) if form.is_valid(): form.save() return redirect(self.get_list_url()) return render(request, "add_view.html",locals()) def delete_view(self, request, id): url = self.get_list_url() if request.method == "POST": self.model.objects.filter(pk=id).delete() return redirect(url) return render(request, "delete_view.html", locals()) def change_view(self, request, id): edit_obj = self.model.objects.filter(pk=id).first() ModelFormDemo=self.get_modelform_class() form = ModelFormDemo(instance=edit_obj) if request.method == "POST": form = ModelFormDemo(request.POST,instance=edit_obj) if form.is_valid(): form.save() return redirect(self.get_list_url()) return render(request, "change_view.html",locals()) #构造 add/delete/change def get_urls2(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label temp = [] temp.append(url(r'^$', self.list_view, name='%s_%s_list'%(app_label,model_name))) temp.append(url(r'^add/', self.add_view, name='%s_%s_add'%(app_label,model_name))) temp.append(url(r'^(\d+)/delete/', self.delete_view, name='%s_%s_delete'%(app_label,model_name))) temp.append(url(r'^(\d+)/change/', self.change_view, name='%s_%s_change'%(app_label,model_name))) return temp @property def urls2(self): return self.get_urls2(), None, None class StarkSite(object): """site单例类""" def __init__(self): self._registry = {} def register(self,model, stark_class=None): """注册""" if not stark_class: stark_class = ModelStark self._registry[model] = stark_class(model,self) def get_urls(self): """构造一层urls app01/book""" temp = [] for model, stark_class_obj in self._registry.items(): print(model, 'stark_clas_obj', stark_class_obj) # 不同的model模型表 """ <class 'app01.models.UserInfo'> ----> <app01.starkadmin.UserConfig object at 0x00000072DDB65198> <class 'app01.models.Book'> ----> <stark.service.stark.ModelStark object at 0x00000072DDB65240> """ app_label = model._meta.app_label # app01 model_name = model._meta.model_name # book # temp.append(url(r'^%s/%s'%(app_label, model_name),([],None,None))) temp.append(url(r'^%s/%s/'%(app_label, model_name),stark_class_obj.urls2)) """ path('app01/userinfo/',UserConfig(Userinfo,site).urls2), path('app01/book/',ModelStark(Book,site).urls2), """ return temp @property def urls(self): # return [],None,None return self.get_urls(),None,None site = StarkSite() # 单例对象
from stark.service import stark from .models import * from django.forms import ModelForm class BookModelForm(ModelForm): class Meta: model = Book fields = "__all__" labels = { "authors":"作者", "publishDate":"出版日期", } class BookConfig(stark.ModelStark): list_display = ['nid', 'title', 'price'] modelform_class = BookModelForm # search_fields = ['title','price'] class AuthorConfig(stark.ModelStark): list_display = ['nid', 'name', 'age'] list_display_links = ['name','age'] stark.site.register(Book,BookConfig) stark.site.register(Publish) stark.site.register(Author,AuthorConfig) stark.site.register(AuthorDetail) print(stark.site._registry) """ {<class 'app01.models.Book'>: <stark.service.stark.ModelStark object at 0x0000003AA7439630>, <class 'app01.models.Publish'>: <stark.service.stark.ModelStark object at 0x0000003AA7439668>, <class 'app01.models.Author'>: <stark.service.stark.ModelStark object at 0x0000003AA74396A0>, <class 'app01.models.AuthorDetail'>: <stark.service.stark.ModelStark object at 0x0000003AA7439940>} """
{% extends 'base.html' %} {% block title %} <title>list页面</title> {% endblock %} {% block header %} <h3>list页面</h3> {% endblock %} {% block content %} <a class="btn btn-primary" href="{{ add_url }}">添加数据</a> {% if show_list.config.search_fields %} <form action="" method="get" class="pull-right"> <input type="text" name="q" value="{{ show_list.config.key_word }}"> <button>submit</button> </form> {% endif %} <table class="table table-bordered table-striped"> <tr> {% for header in show_list.get_header %} {# {% for header in header_list %}#} <th>{{ header }}</th> {% endfor %} </tr> {% for data in show_list.get_body %} {# {% for data in new_data_list %}#} <tr> {% for item in data %} <td>{{ item }}</td> {% endfor %} </tr> {% endfor %} </table> <nav> <ul class="pagination"> {{ show_list.pagination.page_html|safe }} </ul> </nav> {% endblock %} {% block javascript %} <script type="text/javascript"> $('#choice').click(function () { if ($(this).prop('checked')) { //对象自身属性中是否具有指定的属性 $('.choice_item').prop("checked", true) } else { $('.choice_item').prop("checked", false) } }) </script> {% endblock %}
4、action批量处理数据
0、必备知识
1、admin的批量初始化
3、starkadmin之actions
4、构建actions数据
5、前端的按钮checkbox,提交数据
6、post提交处理 数据
6、starkadmin.py
from django.shortcuts import HttpResponse from stark.service import stark from .models import * from django.forms import ModelForm class AuthorConfig(stark.ModelStark): list_display = ['nid', 'name', 'age'] list_display_links = ['name','age'] class BookModelForm(ModelForm): class Meta: model = Book fields = "__all__" labels = { "authors":"作者", "publishDate":"出版日期", } class BookConfig(stark.ModelStark): list_display = ['nid', 'title', 'price'] modelform_class = BookModelForm search_fields = ['title','price'] # 批量修改数据 def patch_init(self,request,queryset): queryset.update(price=111) # return HttpResponse("批量初始化OK") patch_init.short_description = "批量初始化" actions = [patch_init] stark.site.register(Book,BookConfig) stark.site.register(Publish) stark.site.register(Author,AuthorConfig) stark.site.register(AuthorDetail) print(stark.site._registry)
7、stark/service /stark
# -*- coding: utf-8 -*- # @Time : 2018/08/17 0017 14:46 # @Author : Venicid from django.conf.urls import url from django.shortcuts import HttpResponse,render,redirect from django.utils.safestring import mark_safe from django.urls import reverse from stark.utils.page import Pagination class ShowList(object): def __init__(self,config, data_list,request): self.config = config # MOdelStark实例对象 self.data_list = data_list # 数据 self.request =request # 分页 data_count = self.data_list.count() current_page = int(self.request.GET.get('page',1)) base_path = self.request.path self.pagination = Pagination(current_page,data_count,base_path,self.request.GET,per_page_num=11, pager_count=11,) # 分页后的数据 self.page_data = self.data_list[self.pagination.start:self.pagination.end] # actions 批量初始化,字段 self.actions = self.config.actions # [patch_init] # 构建数据[{'name':'path_init',"desc":'xxxxx'}] def get_action_list(self): """action批量初始化,构架数据""" temp = [] for action in self.actions: temp.append( {'name':action.__name__, # class的类名 "desc":action.short_description # class的属性 } ) return temp def get_header(self): # 构建表头 header_list = [] # # header_list = ['选择','pk',...'操作','操作'] for field in self.config.new_list_play(): if callable(field): # header_list.append(field.__name__) val = field(self.config, header=True) header_list.append(val) else: if field == "__str__": header_list.append(self.config.model._meta.model_name.upper()) else: val = self.config.model._meta.get_field(field).verbose_name # 中文名称 header_list.append(val) return header_list def get_body(self): # 构建表单 new_data_list = [] for obj in self.page_data: #分页后的数据 # Book表模型,Author表模型 temp = [] for field in self.config.new_list_play(): # ['name','age'] if callable(field): # edit() 可调用的 print(obj,99999999999999999) val = field(self.config,obj) # 直接调用edit()函数 print('val--------->',val) else: val = getattr(obj,field) # 反射 obj是实例对象,name是方法 # list_display_links 按钮 if field in self.config.list_display_links: model_name = self.config.model._meta.model_name app_label = self.config.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) # print(_url) val = mark_safe("<a href='%s'>%s</a>"%(_url,field)) temp.append(val) new_data_list.append(temp) print('new_data_list',new_data_list) # 构造数据 [['jack', 44], ['mark', 33]] return new_data_list class ModelStark(object): list_display = ["__str__"] # 子类中没有,直接用父类自己的 list_display_links = [] modelform_class = [] search_fields = [] # 模糊查询字段 actions = [] def __init__(self,model, site): self.model = model self.site = site # 增删改查url def get_add_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_add" %(app_label,model_name)) return _url def get_list_url(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_list" %(app_label,model_name)) return _url # 复选框,编辑,删除 def checkbox(self,obj=None, header=False): if header: return mark_safe("<input id='choice' type='checkbox'>") return mark_safe("<input class='choice_item' type='checkbox' name='selected_pk' value='%s'>"%obj.pk) def edit(self,obj=None, header=False): if header: return "操作" # 方案1:固定url # return mark_safe("<a href=/stark/app01/userinfo/%s/change>编辑</a>") # 方案2:拼接url # return mark_safe("<a href='%s/change'>编辑</a>") # 方案3:反向解析 model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change"%(app_label,model_name),args=(obj.pk,)) # print("_url",_url) return mark_safe("<a href='%s'>编辑</a>"%_url) def deletes(self,obj=None, header=False): if header: return "操作" model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_delete"%(app_label,model_name),args=(obj.pk,)) return mark_safe("<a href='%s'>删除</a>"%_url) # ModelForm组件渲染 list、增、删、改页面 def get_modelform_class(self): """ModelForm组件""" if not self.modelform_class: from django.forms import ModelForm class ModelFormDemo(ModelForm): class Meta: model = self.model fields = "__all__" return ModelFormDemo else: return self.modelform_class def new_list_play(self): """构建 ['checkbox','pk', 'name', 'age', edit,'delete']""" temp = [] temp.append(ModelStark.checkbox) temp.extend(self.list_display) if not self.list_display_links: temp.append(ModelStark.edit) temp.append(ModelStark.deletes) return temp ''' def list_view(self,request): ret1 = self.model.objects.filter(title__startswith='py') ret2 = self.model.objects.filter(price__in=[11,22,33,44,55]) ret3 = self.model.objects.filter(price__range=[10,20]) ret4 = self.model.objects.filter(title__contains='O') ret5 = self.model.objects.filter(title__icontains='O') return HttpResponse("过滤成功") ''' def get_search_condition(self,request): """search模糊查询""" key_word = request.GET.get("q",'') self.key_word = key_word from django.db.models import Q # 与或非 search_connection = Q() if key_word: search_connection.connector = "or" for search_field in self.search_fields: search_connection.children.append((search_field+"__contains", key_word)) return search_connection def list_view(self, request): if request.method == 'POST': print('post',request.POST) action = request.POST.get("action") # action': ['patch_init'], if action: selected_pk = request.POST.getlist('selected_pk') # 'selected_pk': ['5']}> action_func = getattr(self,action) # 反射查询 action queryset = self.model.objects.filter(pk__in=selected_pk) # 查询 ret = action_func(request,queryset) # 执行action() # return ret # 获取search的Q对象 search_connection = self.get_search_condition(request) # 筛选获取当前表所有数据 data_list = self.model.objects.all().filter(search_connection) #按照showlist展示页面, 构建表头,表单 show_list = ShowList(self,data_list,request) # self=ModelSTark实例对象 # 构建一个查看addurl add_url = self.get_add_url() return render(request,'list_view.html', locals()) def add_view(self, request): ModelFormDemo=self.get_modelform_class() form = ModelFormDemo() if request.method == "POST": form = ModelFormDemo(request.POST) if form.is_valid(): form.save() return redirect(self.get_list_url()) return render(request, "add_view.html",locals()) def delete_view(self, request, id): url = self.get_list_url() if request.method == "POST": self.model.objects.filter(pk=id).delete() return redirect(url) return render(request, "delete_view.html", locals()) def change_view(self, request, id): edit_obj = self.model.objects.filter(pk=id).first() ModelFormDemo=self.get_modelform_class() form = ModelFormDemo(instance=edit_obj) if request.method == "POST": form = ModelFormDemo(request.POST,instance=edit_obj) if form.is_valid(): form.save() return redirect(self.get_list_url()) return render(request, "change_view.html",locals()) #构造 add/delete/change def get_urls2(self): model_name = self.model._meta.model_name app_label = self.model._meta.app_label temp = [] temp.append(url(r'^$', self.list_view, name='%s_%s_list'%(app_label,model_name))) temp.append(url(r'^add/', self.add_view, name='%s_%s_add'%(app_label,model_name))) temp.append(url(r'^(\d+)/delete/', self.delete_view, name='%s_%s_delete'%(app_label,model_name))) temp.append(url(r'^(\d+)/change/', self.change_view, name='%s_%s_change'%(app_label,model_name))) return temp @property def urls2(self): return self.get_urls2(), None, None class StarkSite(object): """site单例类""" def __init__(self): self._registry = {} def register(self,model, stark_class=None): """注册""" if not stark_class: stark_class = ModelStark self._registry[model] = stark_class(model,self) def get_urls(self): """构造一层urls app01/book""" temp = [] for model, stark_class_obj in self._registry.items(): print(model, 'stark_clas_obj', stark_class_obj) # 不同的model模型表 """ <class 'app01.models.UserInfo'> ----> <app01.starkadmin.UserConfig object at 0x00000072DDB65198> <class 'app01.models.Book'> ----> <stark.service.stark.ModelStark object at 0x00000072DDB65240> """ app_label = model._meta.app_label # app01 model_name = model._meta.model_name # book # temp.append(url(r'^%s/%s'%(app_label, model_name),([],None,None))) temp.append(url(r'^%s/%s/'%(app_label, model_name),stark_class_obj.urls2)) """ path('app01/userinfo/',UserConfig(Userinfo,site).urls2), path('app01/book/',ModelStark(Book,site).urls2), """ return temp @property def urls(self): # return [],None,None return self.get_urls(),None,None site = StarkSite() # 单例对象
8、list_view.html
{% extends 'base.html' %} {% block title %} <title>list页面</title> {% endblock %} {% block header %} <h3>list页面</h3> {% endblock %} {% block content %} <p><a class="btn btn-primary" href="{{ add_url }}">添加数据</a></p> {% if show_list.config.search_fields %} <form action="" method="get" class="pull-right"> <input type="text" name="q" value="{{ show_list.config.key_word }}"> <button>submit</button> </form> {% endif %} <form action="" method="post"> {% csrf_token %} {% if show_list.get_action_list %} <select name="action" id="" style="display: inline-block;width: 200px;margin: 8px 8px 8px 0;height: 25px"> {% for item in show_list.get_action_list %} <option value="">-------</option> <option value="{{ item.name }}">{{ item.desc }}</option> {% endfor %} </select> <button type="submit" class="btn btn-default">Go</button> {% endif %} <table class="table table-bordered table-striped"> <tr> {% for header in show_list.get_header %} {# {% for header in header_list %}#} <th>{{ header }}</th> {% endfor %} </tr> {% for data in show_list.get_body %} {# {% for data in new_data_list %}#} <tr> {% for item in data %} <td>{{ item }}</td> {% endfor %} </tr> {% endfor %} </table> </form> <nav> <ul class="pagination"> {{ show_list.pagination.page_html|safe }} </ul> </nav> {% endblock %} {% block javascript %} <script type="text/javascript"> $('#choice').click(function () { if ($(this).prop('checked')) { //对象自身属性中是否具有指定的属性 $('.choice_item').prop("checked", true) } else { $('.choice_item').prop("checked", false) } }) </script> {% endblock %}
4、总结
1、分页知识点
1.分页
{{ showlist.pagination.page_html|safe }}
2.page.py
class Pagination(object):
def __init__(self, current_page, all_count, base_url,params, per_page_num=8, pager_count=11):
"""
封装分页相关数据
:param current_page: 当前页
:param all_count: 数据库中的数据总条数
:param per_page_num: 每页显示的数据条数
:param base_url: 分页中显示的URL前缀
:param pager_count: 最多显示的页码个数
:param params: ? 后面携带得参数 request.GET
"""
...
注意:翻页时,http://127.0.0.1:8090/stark/app01/publish/?page=2&name=alice&age=18
每页需带上之前的参数。
import copy
params = copy.deepcopy(params)
params._mutable = True
self.params = params # self.params : {"page":77,"title":"python","nid":1}
self.params["page"] = i
self.params.urlencode() 将{"name":"alice","age":18} 转换成 name=alice&age=18
temp = '<li><a href="%s?%s">%s</a></li>' % (self.base_url, self.params.urlencode(), i,)
3.list_view 视图函数
表头,表数据,分页... 内容太多,封装在一个类里面专门用来展示数据。
# 展示数据
showlist = ShowList(self, data_list, request)
class ShowList(object):
def __init__(self):
pass
def get_header(self):
pass
def get_body(self):
pass
2、search模糊查询
1.判断用户是否配置,配置才显示search框, get查询
search_fields = ['title', 'price']
显示key_words{{ showlist.config.key_words }}
{% if showlist.config.search_fields %}
<form action="" class="pull-right">
<input type="text" name="q" value="{{ showlist.config.key_words }}"><button>submit</button>
</form>
{% endif %}
2.Q对象
# 获取search得Q对象
search_connection = self.get_search_condition(request)
# print("connection:",search_connection)
# connection: (or: ('title__contains', '3'), ('price__contains', '3'))
# 筛选当前表得所有数据
data_list = self.model.objects.all().filter(search_connection)
3.Q查询
两种方式,一种可以放str,就是下面这种,一种放字段;
def get_search_condition(self, request):
key_words = request.GET.get('q', "")
self.key_words = key_words
# self.search_fields ['title','price']
from django.db.models import Q
search_connection = Q()
if key_words:
search_connection.connector = "or"
for search_field in self.search_fields:
search_connection.children.append((search_field+"__contains", key_words))
return search_connection
4.模糊查询
(title__contains)(price__contains)
search_connection.children.append((search_field+"__contains", key_words))
3、action批量初始化
知识点
1.用户可自定义配置
def patch_init(self, request, queryset):
# print("queryset",queryset)
queryset.update(price=123)
# return HttpResponse('批量初始化OK')
patch_init.short_description = "批量初始化"
actions = [patch_init]
2.无论有没有配置,都会有一个默认得批量删除
def patch_delete(self, request, queryset):
queryset.delete()
patch_delete.short_description = "批量删除"
def new_actions(self):
temp = []
temp.append(ModelStark.patch_delete)
temp.extend(self.actions)
return temp
3.展示页面 option
传过去得数据: __name__ (方法名传过去,做为value,为之后反射做准备)
self.actions = self.config.new_actions()
def get_action_list(self):
temp = []
for action in self.actions:
temp.append({
"name": action.__name__,
"desc":action.short_description
})
return temp
4.前端
主要就是将:方法名赋值给option得value, form post请求,将值传到后台
<select name="action" id="" style="width: 200px; padding: 5px 8px; display: inline-block; ">
<option value="">------------</option>
{% for item in showlist.get_action_list %}
<option value="{{ item.name }}">{{ item.desc }}</option>
{% endfor %}
</select>
5.后台
接收用户选中得数据,action selected_pk
反射:action_func = getattr(self, action)
过滤查询:queryset: queryset = self.model.objects.filter(pk__in=selected_pk)
执行反射回来得函数: action_func(request, queryset)
def list_view(self, request):
if request.method == "POST":
print("request.POST:",request.POST)
# 'action': ['patch_init'], 'selected_pk': ['1', '2']
action = request.POST.get('action')
selected_pk = request.POST.getlist('selected_pk')
action_func = getattr(self, action) # 反射
queryset = self.model.objects.filter(pk__in=selected_pk) # 秒!!!
ret = action_func(request, queryset)
# return ret
...