crm04 action操作 和 多级过滤
# -*- coding: utf-8 -*- # @Time : 2019/4/12 11:51 # @Author : xxx # @Email : xxx@admin.com # @File : sites.py # @Software: PyCharm from django.urls import path,re_path from django.shortcuts import HttpResponse,render,redirect from app01.models import * from django.utils.safestring import mark_safe from django.core.exceptions import FieldDoesNotExist from django.urls import reverse from django.db.models import Q class ShowList(object): def __init__(self,request,config_obj,queryset): self.config_obj=config_obj self.queryset=queryset self.request=request self.pager_queryset=self.get_pager_queryset() def get_pager_queryset(self): from stark.utils.page import Pagination current_page = self.request.GET.get("page", 1) self.pagination = Pagination(self.request, current_page, self.queryset, per_page_num=self.config_obj.per_page_num or 5) queryset = self.queryset[self.pagination.start:self.pagination.end] return queryset def get_header(self): ''' 获取表头 :return: ''' # 构建表头 header_list = [] for field_or_func in self.config_obj.get_new_list_display(): if callable(field_or_func): val = field_or_func(self.config_obj, header=True) header_list.append(val) # header_list.append(field_or_func.__name__) else: if field_or_func == "__str__": val = self.config_obj.model._meta.model_name.upper() print(val) else: field_obj = self.config_obj.model._meta.get_field(field_or_func) val = field_obj.verbose_name header_list.append(val) return header_list def get_body(self): ''' 获取标体 :return: ''' # 构建展示数据 new_data = [] for obj in self.pager_queryset: temp = [] for field_or_func in self.config_obj.get_new_list_display(): # ["title","price","state","publish",show_authors] if callable(field_or_func): # field:方法 val = field_or_func(self.config_obj, obj) else: try: # field:字符串 from django.db.models.fields.related import ManyToManyField field_obj = self.config_obj.model._meta.get_field(field_or_func) # 判断是否多对多字段 if type(field_obj) == ManyToManyField: raise Exception("list_display不能是多对多字段!") # 判断字段是否 拥有choices属性 if field_obj.choices: val = getattr(obj, "get_%s_display" % field_or_func)() else: val = getattr(obj, field_or_func) if field_or_func in self.config_obj.list_display_links: val = mark_safe("<a href='%s'>%s</a>" % (self.config_obj.get_change_url(obj), val)) except FieldDoesNotExist as e: # val=obj val = getattr(obj, field_or_func)() temp.append(val) new_data.append(temp) print("new_data", new_data) # [['python', Decimal('123.00')], ['java', Decimal('234.00')]] ''' 目标数据结构 new_data=[ ["python",123], ["java",234] ] ''' return new_data class ModelStark(object): ''' 默认配置类 ''' list_display=("__str__",) list_display_links = [] model_form_class=None per_page_num=None search_fields=[] search_val=None list_filter=[] def __init__(self,model): self.model=model self.model_name = self.model._meta.model_name self.app_label = self.model._meta.app_label # 反向解析当前访问表的增删改查URL def get_list_url(self): # 反向解析当前表的删除的URL list_url = reverse("%s_%s_list" % (self.app_label, self.model_name)) return list_url def get_add_url(self): # 反向解析当前表的删除的URL add_url = reverse("%s_%s_add" % (self.app_label, self.model_name)) return add_url def get_delete_url(self,obj): # 反向解析当前表的删除的URL delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,)) return delete_url def get_change_url(self, obj): # 反向解析当前表的删除的URL change_url = reverse("%s_%s_change" % (self.app_label, self.model_name), args=(obj.pk,)) return change_url # 三个默认列 def show_checkbox(self, obj=None, header=False): if header: return mark_safe("<input type='checkbox'>") return mark_safe("<input name='_selected_action' value=%s type='checkbox'>"%obj.pk) def show_delbtn(self, obj=None, header=False): if header: return "删除" return mark_safe("<a href='%s'>删除</a>"%self.get_delete_url(obj)) def show_editbtn(self, obj=None, header=False): if header: return "编辑" return mark_safe("<a href='%s'>编辑</a>" %self.get_change_url(obj)) # 构建新的list_display def get_new_list_display(self): temp=[] temp.extend(self.list_display) temp.append(ModelStark.show_editbtn) temp.append(ModelStark.show_delbtn) temp.insert(0,ModelStark.show_checkbox) return temp def get_search_condition(self,request): val = request.GET.get("q") q = Q() if val: self.search_val = val q.connector = "or" for field in self.search_fields: # ["title","price"] print(field) # queryset=queryset.filter(Q(title__contains=val)|Q(price__contains=val)) q.children.append((field + "__contains", val)) else: self.search_val=None return q # def get_search_links(self): # import copy # params = copy.deepcopy(self.request.GET) # {"publish":1,"authors":1} # search_button = "<a class='btn btn-primary' href='?%s'>Search!</a>" % params.urlencode() # return search_button #################### action操作 ############################### # action参数 def patch_delete(self,request,queryset): # [1,3] queryset.delete() patch_delete.desc="批量删除" actions=[] def get_new_actions(self): temp=[] temp.extend(self.actions) temp.append(self.patch_delete) return temp def get_action_dict(self): actions_list=[] for func in self.get_new_actions(): actions_list.append({ "name":func.__name__, "desc":func.desc, }) return actions_list # [{"name":"patch_delete","desc":"批量删除"}] #################### 多筛选操作 ############################### def get_list_filter_links(self): list_filter_links={} print(self.list_filter) # ["publish","authors","state"] for filter_field in self.list_filter: import copy params = copy.deepcopy(self.request.GET) # {"publish":1,"authors":1} current_field_val=params.get(filter_field) print('params--->',params) #params---> <QueryDict: {}> http://127.0.0.1:8000/stark/app01/book/ filter_field_obj=self.model._meta.get_field(filter_field) #获取模型类的字段类对象 eg:state = models.IntegerField(choices=[(1,"已出版"),(2,"未出版社")],default=1) print(">>>",type(filter_field_obj)) #["publish","authors","state"]---><class 'django.db.models.fields.related.ForeignKey'>,<class 'django.db.models.fields.related.ManyToManyField'>,<class 'django.db.models.fields.IntegerField'> from django.db.models.fields.related import ForeignKey,ManyToManyField # 针对一对多或者多对多过滤字段 if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField): print(filter_field_obj.remote_field)#["publish","authors","state"]---><ManyToOneRel: app01.book>,<ManyToManyRel: app01.book>, print("____>",filter_field_obj.remote_field.model) # eg:<class 'app01.models.Publish'> 找到 模型类的字段类对象 的那个字段类 eg:state--->IntegerField publish---> Publish #["publish","authors","state"]---><class 'app01.models.Publish'>,<class 'app01.models.Author'>, data=filter_field_obj.remote_field.model.objects.all() # eg:<QuerySet [<Publish: 苹果出版设>, <Publish: 橘子出版设>, <Publish: 西瓜出版社>]> print(data) elif filter_field_obj.choices: # print(filter_field_obj.remote_field) None # 针对choice字段类型 data=filter_field_obj.choices # eg:[(1,"已出版"),(2,"未出版社")] else: raise Exception("过滤字段不能太普通!") # 为每一个数据构建成一个a标签 temp = [] # params2=copy.deepcopy(params) if params.get(filter_field): #对list_filter_links和params.urlencode()的影响 del params[filter_field] all = "<a class='btn btn-default btn-sm' href='?%s'>全部</a>"%params.urlencode() #用户点击时 所有的 temp.append(all) for item in data: if type(item)==tuple: # 元组类型 pk,text = item else: # model对象类型 pk,text = item.pk,str(item) params[filter_field]=pk # *********** _url="?%s"%(params.urlencode()) # *********** print('url',_url) if current_field_val==str(pk): link="<a class='active btn btn-default btn-sm' href='%s'>%s</a>"%(_url,text) else: link = "<a class='btn btn-default btn-sm' href='%s'>%s</a>" % (_url, text) temp.append(link) list_filter_links[filter_field]=temp # print('hahhahaha',list_filter_links) ''' print('hahhahaha',list_filter_links) hahhahaha { 'publish': ["<a class='btn btn-default btn-sm' href='?'>全部</a>", "<a class='btn btn-default btn-sm' href='?publish=1'>苹果出版设</a>", "<a class='btn btn-default btn-sm' href='?publish=2'>橘子出版设</a>", "<a class='btn btn-default btn-sm' href='?publish=3'>西瓜出版社</a>"], 'authors': ["<a class='btn btn-default btn-sm' href='?'>全部</a>", "<a class='btn btn-default btn-sm' href='?authors=1'>alex</a>", "<a class='btn btn-default btn-sm' href='?authors=2'>egon</a>"], 'state': ["<a class='btn btn-default btn-sm' href='?'>全部</a>", "<a class='btn btn-default btn-sm' href='?state=1'>已出版</a>", "<a class='btn btn-default btn-sm' href='?state=2'>未出版社</a>"]} ''' return list_filter_links def get_list_filter_condition(self): q=Q() for filter_field,val in self.request.GET.items(): if filter_field in ["page","q"]:continue q.children.append((filter_field,val)) return q ########################################################################################### # 视图函数 def list_view(self,request): ''' self: 当前访问模型表对应的配置类对象 self.model: 当前访问模型表 :param request: :return: ''' self.request=request if request.method=="POST": # action操作 action_func_str=request.POST.get("action") if action_func_str: action_func=getattr(self,action_func_str) _selected_action=request.POST.getlist("_selected_action") # [1,3] queryset=self.model.objects.filter(pk__in=_selected_action) action_func(request,queryset) queryset=self.model.objects.all() # search过滤 search_condition=self.get_search_condition(request) # list_filter多级过滤+ list_filter_condition=self.get_list_filter_condition() queryset=queryset.filter(search_condition).filter(list_filter_condition) show_list=ShowList(request,self,queryset) # 相关变量 table_name=self.model._meta.verbose_name add_url=self.get_add_url() return render(request,'stark/list_view.html',locals()) def get_model_form(self): from django.forms import ModelForm class BaseModelForm(ModelForm): class Meta: model = self.model fields = "__all__" return self.model_form_class or BaseModelForm def add_view(self,request): BaseModelForm=self.get_model_form() if request.method=="GET": form_obj=BaseModelForm() return render(request,"stark/add_view.html",locals()) else: form_obj = BaseModelForm(request.POST) if form_obj.is_valid(): form_obj.save() return redirect(self.get_list_url()) else: return render(request, "stark/add_view.html", locals()) def change_view(self,request,id): BaseModelForm=self.get_model_form() edit_obj=self.model.objects.filter(pk=id).first() if request.method=="GET": form_obj=BaseModelForm(instance=edit_obj) return render(request,"stark/change_view.html",locals()) else: form_obj = BaseModelForm(request.POST,instance=edit_obj) if form_obj.is_valid(): form_obj.save() return redirect(self.get_list_url()) else: return render(request, "stark/change_view.html", locals()) def delete_view(self,request, id): if request.method=="POST": self.model.objects.filter(pk=id).delete() return redirect(self.get_list_url()) list_url=self.get_list_url() return render(request,"stark/delete_view.html",locals()) @property def get_urls(self): temp = [ path("", self.list_view,name="%s_%s_list"%(self.app_label,self.model_name)), path("add/", self.add_view,name="%s_%s_add"%(self.app_label,self.model_name)), re_path("(\d+)/change/", self.change_view,name="%s_%s_change"%(self.app_label,self.model_name)), re_path("(\d+)/delete/", self.delete_view,name="%s_%s_delete"%(self.app_label,self.model_name)), ] return (temp, None, None) class StarkSite: ''' stark全局类 ''' def __init__(self): self._registry = {} def register(self, model, admin_class=None, **options): admin_class = admin_class or ModelStark self._registry[model] = admin_class(model) def get_urls(self): # 动态为注册的模型类创建增删改查URL temp = [] # {Book:ModelAdmin(Book),Publish:ModelAdmin(Publish)} for model, config_obj in self._registry.items(): print("---->", model, config_obj) model_name = model._meta.model_name app_label = model._meta.app_label temp.append( path("%s/%s/" % (app_label,model_name),config_obj.get_urls) ) ''' path("stark/app01/book",BookConfig(Book).list_view) path("stark/app01/book/add",BookConfig(Book).add_view) path("stark/app01/publish",ModelAdmin(Publish).list_view) path("stark/app01/publish/add",ModelAdmin(Publish).add_view) ''' return temp @property def urls(self): return self.get_urls(),None,None site = StarkSite()
# -*- coding: utf-8 -*- # @Time : 2019/4/12 11:47 # @Author : xxx # @Email : xxx@admin.com # @File : stark.py # @Software: PyCharm from stark.service.sites import site,ModelStark from .models import * from django.utils.safestring import mark_safe from django.forms import ModelForm class BookModelForm(ModelForm): class Meta: model=Book fields="__all__" error_messages={ "title":{ "required":" 该字段不能为空!"} } class BookConfig(ModelStark): def show_authors(self,obj=None,header=False): if header: return "作者信息" return " ".join([author.name for author in obj.authors.all()]) list_display=["title","price","state","publish",show_authors] list_display_links=["title","price"] model_form_class=BookModelForm per_page_num=3 search_fields=["title","price"] # action参数 def patch_init(self, request, queryset): queryset.update(price=0) patch_init.desc = "价格初始化" actions = [patch_init, ] list_filter=["publish","authors","state"] site.register(Book,BookConfig) site.register(Publish) # print(site._registry)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> <style> .filter_body { padding: 16px; margin: 40px; margin-bottom: -20px; } .filter_body_item { margin-bottom: 10px; } .filter_body .active { background-color: #000; color: white; } </style> </head> <body> <h3>查看数据</h3> <div class="container"> <div class="row"> <div class="panel panel-info"> <div class="panel-heading"> <h3 class="panel-title"></h3> </div> <div class="panel-body"> <a href="{{ add_url }}" class="btn btn-primary">添加{{ table_name }}</a> {% if show_list.config_obj.search_fields %} <form action="" method="get"> <div class="input-group pull-right" style="width: 400px"> <input value="{{ show_list.config_obj.search_val|default:'' }}" type="text" name="q" class="form-control" placeholder="Search for..."> <span class="input-group-btn"> <button class="btn btn-primary">Search!</button> </span> </div> </form> {% endif %} <div> <div class="panel-default filter_body"> {% for field,links in show_list.config_obj.get_list_filter_links.items %} <div class="filter_body_item"> <span class="btn btn-default btn-sm" style="width: 100px">按{{ field }}筛选</span> {% for link in links %} {{ link|safe }} {% endfor %} </div> {% endfor %} </div> </div> </div> </div> <form action="" method="post"> {% csrf_token %} <div class="action"> <select class="form-control" name="action" id="" style="width: 250px;display: inline-block;vertical-align: -2px;"> <option value="">-------------------------------------------</option> {% for action in show_list.config_obj.get_action_dict %} <option value="{{ action.name }}">{{ action.desc }}</option> {% endfor %} </select> <button class="btn btn-primary" style="margin-left: -4px">Go!</button> </div> <table class="table table-striped"> <thead> <tr> {% for item in show_list.get_header %} <th>{{ item }}</th> {% endfor %} </tr> </thead> <tbody> {% for item in show_list.get_body %} <tr> {% for info in item %} <td>{{ info }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </form> <div class="pull-right"> {{ show_list.pagination.page_html|safe }} </div> </div> </div> </body> </html>