基于admin自定义stark组件
在stark里面代码
from django.conf.urls import url from django.shortcuts import redirect, render from django.urls import reverse from django.utils.safestring import mark_safe # 渲染成html页面 class ModelStark(): # 默认配置类对象 def __init__(self, model): self.model = model self.model_name = self.model._meta.model_name self.app_label = self.model._meta.app_label self.app_model_name = (self.app_label, self.model_name) list_display = ["__str__"] list_display_links = [] # 默认的进入编辑, model_form_class = [] # 默认的错误提示英文 # 方式1 # 反向解析出增删改查的url # # 删除url # def get_delete_url(self,obj): # url_name = "%s_%s_delete" % self.app_model_name # _url = reverse(url_name, args=(obj.pk,)) # # return _url # # # 编辑url # def get_change_url(self, obj): # url_name = "%s_%s_change" % self.app_model_name # _url = reverse(url_name, args=(obj.pk,)) # # return _url # # # # 查看url # def get_list_url(self): # url_name = "%s_%s_list" % self.app_model_name # _url = reverse(url_name) # # return _url # # # 添加url # def get_add_url(self, obj): # url_name = "%s_%s_add" % self.app_model_name # _url = reverse(url_name, args=(obj.pk,)) # # return _url # # # 方式2反向解析 def get_reverse_url(self, type, obj=None): # obj默认为空,因为我们只拼接了,app和表名 type:代表点击的增删查改 url_name = "%s_%s_%s" % (self.app_label, self.model_name, type) # 拼接出地址 if obj: _url = reverse(url_name, args=(obj.pk,)) # 把地址传进来,还有有的url是动态的我们可以用一个元祖,把唯一id传进来 else: _url = reverse(url_name) # 如果没有动态的,直接拼接地址 return _url # 选择,删除,编辑按钮 def delete_col(self, obj=None, is_header=False): if is_header: return "删除" return mark_safe("<a href='%s'>删除</a>" % self.get_reverse_url("delete", obj)) def edit_col(self, obj=None, is_header=False): if is_header: print(is_header) return "编辑" return mark_safe("<a href='%s'>编辑</a>" % (self.get_reverse_url("change", obj))) def check_col(self, obj=None, is_header=False): if is_header: return "选择" return mark_safe("<input type='checkbox'>") def get_new_list_display(self): # 把上面的放在一个字典里面 new_list_display = [] new_list_display.extend(self.list_display) if not self.list_display_links: # 如果没有自定义的就用默认编辑, # extend把两个列表里面放一起 new_list_display.append(ModelStark.edit_col) new_list_display.append(ModelStark.delete_col) new_list_display.insert(0, ModelStark.check_col) return new_list_display def list_view(self, request): """ data_list = [ ["书",122], ] :param request: :return: """ # 用户访问的模型表: self.model print("self.model:", self.model) queryset = self.model.objects.all() print("self.list_display", self.list_display) # ["nid","title","price","publish"] # 处理表头 # header_list=["名称","价格","出版社"] header_list = [] for field_or_func in self.get_new_list_display(): # ["title","price","publish",delete_col] if isinstance(field_or_func, str): if field_or_func == "__str__": val = self.model._meta.model_name.upper() else: field_obj = self.model._meta.get_field(field_or_func) val = field_obj.verbose_name # 表头怎么定义中文就是中文,不定义就是英文?Verbose_name=“中文” 新的语法:book._meta.get_field("title") title可以点里面的字段对象 现在可以定义了: else: val = field_or_func(self, is_header=True) header_list.append(val) # 处理表单数据 data_list = [] for obj in queryset: # [obj1,obj2,obj3] temp = [] for field_or_func in self.get_new_list_display(): # list_display = ["title","price","publish",delete_col] if isinstance(field_or_func, str): val = getattr(obj, field_or_func) if field_or_func in self.list_display_links: val = mark_safe("<a href='%s'>%s</a>" % (self.get_reverse_url("change", obj), val)) else: val = field_or_func(self, obj) temp.append(val) data_list.append(temp) print(data_list) # 获取添加url add_url = self.get_reverse_url("add") return render(request, "stark/list_view.html", {"data_list": data_list, "header_list": header_list, "add_url": add_url}) def get_model_form_class(self): # 把自定义的提示中文和modelForm封装成函数 if self.model_form_class: # 如果有自定义的提示中文 return self.model_form_class else: from django import forms class ModelFormDemo(forms.ModelForm): # 帮我们把model 字段都转换form里面的字段 class Meta: model = self.model fields = "__all__" return ModelFormDemo def add_view(self, request): """ if GET请求: GET请求: form = BookModelForm() form:渲染 if POST请求: form = BookModelForm(request.POST) form.is_valid() form.save() # 添加数据 create :param request: :return: """ ModelFormDemo = self.get_model_form_class() # 验证get_model_form_class拿到 if request.method == "GET": form = ModelFormDemo() return render(request, "stark/add_view.html", locals()) # locals 就是相当于一个元祖传值 else: form = ModelFormDemo(request.POST) if form.is_valid(): # 做校验 form.save() # 这个的save相当于create return redirect(self.get_reverse_url("list")) else: return render(request, "stark/add_view.html", locals()) def change_view(self, request, id): """ edit_book = Book.objects.get(pk=id) GET: form = BookModelForm(instance=edit_book) form:渲染 POST: form = BookModelForm(request.POST, instance=edit_book) form.is_valid form.save() # 更新数据 update :param request: :param id: :return: """ ModelFormDemo = self.get_model_form_class() edit_obj = self.model.objects.get(pk=id) if request.method == "GET": form = ModelFormDemo(instance=edit_obj) return render(request, "stark/change_view.html", locals()) else: form = ModelFormDemo(data=request.POST, instance=edit_obj) # instance 方法就是决定了是更新还是添加,有就是更新 if form.is_valid(): # 做校验 form.save() # 这里相当于create return redirect(self.get_reverse_url("list")) # 返回list else: return render(request, "stark/change_view.html", locals()) def delete_view(self, request, id): if request.method == "POST": self.model.objects.get(pk=id).delete() return redirect(self.get_reverse_url("list")) list_url = self.get_reverse_url("list") return render(request, "stark/delete_view.html", locals()) def get_urls(self): temp = [ url("^$", self.list_view, name="%s_%s_list" % (self.app_model_name)), # 取别名 取别名app+表名是唯一的 url("^add/$", self.add_view, name="%s_%s_add" % (self.app_model_name)), url("^(\d+)/change/$", self.change_view, name="%s_%s_change" % (self.app_model_name)), url("^(\d+)/delete/$", self.delete_view, name="%s_%s_delete" % (self.app_model_name)), 后面不只一个参数是动态数据 ] return temp @property def urls(self): return self.get_urls(), None, None class StarkSite(object): def __init__(self, name='admin'): self._registry = {} def register(self, model, admin_class=None, **options): if not admin_class: #如果自己没有配置 admin_class = ModelStark # 配置类 self._registry[model] = admin_class(model) # 拿到键值对 # {Book:BookConfig(Book),Publish:ModelAdmin(Publish)} def get_urls(self): temp = [ ] for model_class, config_obj in self._registry.items(): print("===>", model_class, config_obj) model_name = model_class._meta.model_name # 拿到表名 app_label = model_class._meta.app_label #拿到所在的app print("===>", app_label, model_name) temp.append(url(r'^%s/%s/' % (app_label, model_name), config_obj.urls))# 配置对象里面调用配置类对象的二级路由 ''' 创建url: url("app01/book/$",self.list_view,name="app01_book_list"), url("app01/book/add$",self.add_view,name="app01_book_add"), url("app01/book/(\d+)/change/$",self.change_view), url("app01/book/(\d+)/delete/$",self.delete_view), url("app01/publish/$",self.list_view,name="app01_publish_list"), url("app01/publish/add$",self.add_view,name="app01_publish_add"), url("app01/publish/(\d+)/change/$",self.change_view), url("app01/publish/(\d+)/delete/$",self.delete_view), ''' return temp @property def urls(self): return self.get_urls(), None, None site = StarkSite() # 这里应用的是一个单例模式,对于AdminSite类的一个单例模式,执行的每一个app中的每一个admin.site都是一个对象 整理2 from django.conf.urls import url from django.db.models import Q from django.shortcuts import redirect, render from django.urls import reverse from django.utils.safestring import mark_safe # 渲染成html页面 from stark.utils.page import Pagination ''' 封装分页相关数据 :param current_page: 当前页 :param all_count: 数据库中的数据总条数 :param per_page_num: 每页显示的数据条数 :param base_url: 分页中显示的URL前缀 :param pager_count: 最多显示的页码个数 ''' class Showlist(object): def __init__(self, conf_obj, queryset, request): # 把配置类对象拿过来,request:从哪里过来的请求,queryset:就是下面showlist传进来的值 self.conf_obj = conf_obj self.queryset = queryset self.request = request # 分页 current_page = self.request.GET.get("page") pagination = Pagination(current_page, self.queryset.count(), self.request.GET, per_page_num=2) self.pagination = pagination self.page_queryset = self.queryset[self.pagination.start:self.pagination.end] # 根据用户访问页码 def get_header(self): # 处理表头 # header_list=["名称","价格","出版社"] header_list = [] for field_or_func in self.conf_obj.get_new_list_display(): # ["title","price","publish",delete_col] if isinstance(field_or_func, str): if field_or_func == "__str__": val = self.conf_obj.model._meta.model_name.upper() else: field_obj = self.conf_obj.model._meta.get_field(field_or_func) val = field_obj.verbose_name # 表头的字段如果用户设置了就显示中文 else: val = field_or_func(self.conf_obj, is_header=True) header_list.append(val) return header_list def get_body(self): # 处理表单数据 data_list = [] for obj in self.page_queryset: # [obj1,obj2,obj3] temp = [] for field_or_func in self.conf_obj.get_new_list_display(): # list_display = ["title","price","publish",delete_col] if isinstance(field_or_func, str): val = getattr(obj, field_or_func) if field_or_func in self.conf_obj.list_display_links: val = mark_safe("<a href='%s'>%s</a>" % (self.conf_obj.get_reverse_url("change", obj), val)) else: val = field_or_func(self.conf_obj, obj) temp.append(val) data_list.append(temp) print(data_list) return data_list # action 批量处理 def get_actions(self): temp = [] for func in self.conf_obj.actions: # [patch_delete,] temp.append({ "name": func.__name__, # 拿到是函数名 "desc": func.desc # 拿到中文翻译 }) return temp # [{"name":"patch_delete","desc":"批量删除"},] # filter操作 def get_filter_links(self): print("self.conf_obj.list_filter", self.conf_obj.list_filter) # ['publish', 'authors'] links_dict = {} for filter_field in self.conf_obj.list_filter: # ['publish', 'authors'] filter_field_obj = self.conf_obj.model._meta.get_field(filter_field) print(filter_field_obj) print(type(filter_field_obj)) print("rel", filter_field_obj.rel.to) queryset = filter_field_obj.rel.to.objects.all() print("queryset", queryset) temp = [] import copy params = copy.deepcopy(self.request.GET) # 渲染标签 current_filter_field_id = self.request.GET.get(filter_field) # all 的链接标签 params2 = copy.deepcopy(self.request.GET) if filter_field in params2: params2.pop(filter_field) all_link = "<a href='?%s'>All</a>" % params2.urlencode() else: all_link = "<a href=''>All</a>" temp.append(all_link) for obj in queryset: params[filter_field] = obj.pk# 判断当前的zd _url = params.urlencode() if current_filter_field_id == str(obj.pk): s = "<a class='item active2' href='?%s'>%s</a>" % (_url, str(obj)) else: s = "<a class='item' href='?%s'>%s</a>" % (_url, str(obj)) temp.append(s) links_dict[filter_field] = temp return links_dict class ModelStark(): # 默认配置类对象 def __init__(self, model): self.model = model self.model_name = self.model._meta.model_name self.app_label = self.model._meta.app_label self.app_model_name = (self.app_label, self.model_name) self.key_word = "" # search 操作设置为空 list_display = ["__str__"] list_display_links = [] # 默认的进入编辑, model_form_class = [] # 默认的错误提示英文 search_fields = [] # 模糊搜索框 actions = [] # 批量初始化 list_filter = [] # filter 对多对多,多对一 做查询 # 方式1 # 反向解析出增删改查的url # # 删除url # def get_delete_url(self,obj): # url_name = "%s_%s_delete" % self.app_model_name # _url = reverse(url_name, args=(obj.pk,)) # # return _url # # # 编辑url # def get_change_url(self, obj): # url_name = "%s_%s_change" % self.app_model_name # _url = reverse(url_name, args=(obj.pk,)) # # return _url # # # # 查看url # def get_list_url(self): # url_name = "%s_%s_list" % self.app_model_name # _url = reverse(url_name) # # return _url # # # 添加url # def get_add_url(self, obj): # url_name = "%s_%s_add" % self.app_model_name # _url = reverse(url_name, args=(obj.pk,)) # # return _url # # # 方式2反向解析 def get_reverse_url(self, type, obj=None): # obj默认为空 url_name = "%s_%s_%s" % (self.app_label, self.model_name, type) # 拼接出地址 if obj: _url = reverse(url_name, args=(obj.pk,)) # 把地址传进来,还有有的url是动态的我们可以用一个元祖,把唯一id传进来 else: _url = reverse(url_name) # 如果没有动态的,直接拼接地址 return _url # 选择,删除,编辑按钮 def delete_col(self, obj=None, is_header=False): if is_header: return "删除" return mark_safe("<a href='%s'>删除</a>" % self.get_reverse_url("delete", obj)) def edit_col(self, obj=None, is_header=False): if is_header: print(is_header) return "编辑" return mark_safe("<a href='%s'>编辑</a>" % (self.get_reverse_url("change", obj))) def check_col(self, obj=None, is_header=False): if is_header: return "选择" return mark_safe("<input type='checkbox' name='selected_action' value='%s'>" % obj.pk) def get_new_list_display(self): # 把上面的放在一个字典里面 new_list_display = [] new_list_display.extend(self.list_display) if not self.list_display_links: # 如果没有自定义的就用默认编辑 new_list_display.append(ModelStark.edit_col) new_list_display.append(ModelStark.delete_col) new_list_display.insert(0, ModelStark.check_col) return new_list_display # search 搜索框 def search_filter(self, request, queryset): # search 操作 key_word = request.GET.get("q") # 拿到搜索框值 print(self.search_fields) # ["title","price"] self.key_word = "" # 判断搜索框里面有没有值 if key_word: self.key_word = key_word # 如果有把值赋给默认的 # 调用q的另外的一个方法拿到值,不然我们普通循环拿到是字符串 search_condition = Q() # 定义一个q所有查询 search_condition.connector = "or" # 拿到的值是一个或的关系 for field in self.search_fields: search_condition.children.append( (field + "__icontains", key_word)) # field+"__icontains"里面包含有key_word有没 queryset = queryset.filter(search_condition) return queryset # FILTER 操作 def filter_list(self, request, queryset): # filter 操作 filter_condition = Q() for key, val in request.GET.items(): # publish=2&authors=1 if key in ["page", "q"]: continue filter_condition.children.append((key, val)) if filter_condition: # 如果输入不合法 try: queryset = queryset.filter(filter_condition) except Exception: pass return queryset def list_view(self, request): """ data_list = [ ["书",122], ] :param request: :return: """ # action 批量处理操作 # action操作 if request.method == "POST": actions = request.POST.get("action") # 拿到选择的方法名 if not actions: pk_list = request.POST.getlist("selected_action") # 通过getlist 拿到所有的id列表 queryset = self.model.objects.filter(pk__in=pk_list) # 筛选选择的那些id func1 = getattr(self, actions) # 通过方法名拿到对应的方法 func1(request, queryset) # 把值传给app01 下的stark 看选择的是哪个 # 用户访问的模型表: self.model print("self.model:", self.model) queryset = self.model.objects.all() print("self.list_display", self.list_display) # ["nid","title","price","publish"] # 处理表头 # search 操作 queryset = self.search_filter(request, queryset) # 分页之后的结果 赋值给queryset,然后下面拿到的就是新的 # filter操作 queryset = self.filter_list(request, queryset) showlist = Showlist(self, queryset, request) # Showlist封装成一个类,前端可以通过showlist点方法 # 获取添加url add_url = self.get_reverse_url("add") return render(request, "stark/list_view.html", locals()) def get_model_form_class(self): # 把自定义的提示中文和modelForm封装成函数 if self.model_form_class: # 如果有自定义的提示中文 return self.model_form_class else: from django import forms class ModelFormDemo(forms.ModelForm): # 帮我们把model 字段都转换form里面的字段 class Meta: model = self.model fields = "__all__" return ModelFormDemo def add_view(self, request): """ if GET请求: GET请求: form = BookModelForm() form:渲染 if POST请求: form = BookModelForm(request.POST) form.is_valid() form.save() # 添加数据 create :param request: :return: """ ModelFormDemo = self.get_model_form_class() # 验证get_model_form_class拿到 from django.forms.models import ModelChoiceField if request.method == "GET": form = ModelFormDemo() # pop开始 for bfield in form: # print(type(bfield.field))拿到对象的是什么类型的字段 if isinstance(bfield.field, ModelChoiceField): # 用isinstance bfield.field是不是ModelChoiceField类型 bfield.is_pop = True # 属性 filed_rel_model = self.model._meta.get_field(bfield.name).rel.to # 拿到字段对象拿到关联表 model_name = filed_rel_model._meta.model_name app_label = filed_rel_model._meta.app_label _url = reverse("%s_%s_add" % (app_label, model_name)) # 反向拿到表和model名字 bfield.url = _url + "?pop_back_id=" + bfield.auto_id # 拼接地址,auto_id 拼接_id 上面的路径 # pop结束 return render(request, "stark/add_view.html", locals()) # locals 就是相当于一个元祖传值 else: form = ModelFormDemo(request.POST) if form.is_valid(): # 做校验 obj = form.save() # 这个的save相当于create,pop赋值给obj拿到 # pop # 判断是不是pop请求弹出框 pop_back_id = request.GET.get("pop_back_id") if pop_back_id: pk = obj.pk text = str(obj) return render(request, "stark/pop.html", locals()) # pop 结束 return redirect(self.get_reverse_url("list")) else: return render(request, "stark/add_view.html", locals()) def change_view(self, request, id): """ edit_book = Book.objects.get(pk=id) GET: form = BookModelForm(instance=edit_book) form:渲染 POST: form = BookModelForm(request.POST, instance=edit_book) form.is_valid form.save() # 更新数据 update :param request: :param id: :return: """ ModelFormDemo = self.get_model_form_class() edit_obj = self.model.objects.get(pk=id) if request.method == "GET": form = ModelFormDemo(instance=edit_obj) return render(request, "stark/change_view.html", locals()) else: form = ModelFormDemo(data=request.POST, instance=edit_obj) # instance 方法就是决定了是更新还是添加,有就是更新 if form.is_valid(): # 做校验 form.save() # 这里相当于create return redirect(self.get_reverse_url("list")) # 返回list else: return render(request, "stark/change_view.html", locals()) def delete_view(self, request, id): if request.method == "POST": self.model.objects.get(pk=id).delete() return redirect(self.get_reverse_url("list")) list_url = self.get_reverse_url("list") return render(request, "stark/delete_view.html", locals()) def get_urls(self): temp = [ url("^$", self.list_view, name="%s_%s_list" % (self.app_model_name)), # 取别名 url("^add/$", self.add_view, name="%s_%s_add" % (self.app_model_name)), url("^(\d+)/change/$", self.change_view, name="%s_%s_change" % (self.app_model_name)), url("^(\d+)/delete/$", self.delete_view, name="%s_%s_delete" % (self.app_model_name)), ] return temp @property def urls(self): return self.get_urls(), None, None class StarkSite(object): def __init__(self, name='admin'): self._registry = {} def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelStark # 配置类 self._registry[model] = admin_class(model) # {Book:BookConfig(Book),Publish:ModelAdmin(Publish)} def get_urls(self): temp = [ ] for model_class, config_obj in self._registry.items(): print("===>", model_class, config_obj) model_name = model_class._meta.model_name app_label = model_class._meta.app_label print("===>", app_label, model_name) temp.append(url(r'^%s/%s/' % (app_label, model_name), config_obj.urls)) ''' 创建url: url("app01/book/$",self.list_view,name="app01_book_list"), url("app01/book/add$",self.add_view,name="app01_book_add"), url("app01/book/(\d+)/change/$",self.change_view), url("app01/book/(\d+)/delete/$",self.delete_view), url("app01/publish/$",self.list_view,name="app01_publish_list"), url("app01/publish/add$",self.add_view,name="app01_publish_add"), url("app01/publish/(\d+)/change/$",self.change_view), url("app01/publish/(\d+)/delete/$",self.delete_view), ''' return temp @property def urls(self): return self.get_urls(), None, None site = StarkSite()
html
add_view
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/commonn.css"> </head> <body> {% include "stark/class_form.html" %} <script> function show_option(pop_back_id,pk,text) { console.log(pop_back_id,pk,text); var option=document.createElement("option"); option.innerHTML=text; option.value=pk; option.selected="selected"; select=document.getElementById(pop_back_id); select.appendChild(option); } </script> </body> </html>
change_view
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/css/commonn.css"> </head> <body> {% include "stark/class_form.html" %} </body> </html>
class_form_view
<div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div class="form-group field_region"> <label for="">{{ field.label }}</label> {{ field }} <span class="erorr pull-right">{{ field.errors.0 }}</span> {# pop开始#} {% if field.is_pop %} <span class="plus"><a onclick="add_option('{{ field.url }}')">+</a></span> {% endif %} </div> {% endfor %} <input type="submit" class="btn btn-default pull-right"> </form> </div> </div> </div> <script> {# 把上面传值进来拿到展示#} function add_option(url) { window.open(url,"","height=500,width=800,top=100,left=100") } </script>
delete_view
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css"> <script src="/static/jquery-3.3.1.min.js"></script> <link rel="stylesheet" href="/static/css/commonn.css"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-3 col-md-offset-3"> <form action="" method="post"> {% csrf_token %} <div class="panel panel-warning"> <div class="panel-heading"> <h3 class="panel-title">确定删除吗</h3> </div> <div class="panel-body"> <input type="submit" class="btn btn-warning" value="确认删除"> <a href="{{ list_url }}"class="btn btn-warning">取消</a> </div> </div> </form> </div> </div> </div> </body> </html>
list_view
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css"> <script src="/static/jquery-3.3.1.min.js"></script> <script src="/static/mystyle.css"></script> <link rel="stylesheet" href="/static/css/commonn.css"> <style> .a { margin-top: -7px; } .action { width: 40%; margin-top: 10px; } .action1 { margin-top: 10px; } .item{ color: gray; } .active2{ color: red; } </style> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-2"> <div class="panel panel-warning"> <div class="panel-heading"> <h3 class="panel-title"> <a href="{{ add_url }}" class=" glyphicon glyphicon-plus"></a> {# search 搜索#} {% if showlist.conf_obj.search_fields %} <form class="form-inline pull-right a "> <div class="input-group"> <div class="input-group"> <input type="text" class="form-control" name="q" value="{{ showlist.conf_obj.key_word }}" placeholder="关键字"> </div> </div> <button type="submit" class="btn btn-warning">Search</button> </form> {% endif %} {# 结束#} </h3> </div> <form action="" class="form-inline" method="post"> {% csrf_token %} <div class="panel-body"> <select class="form-control action action " name="action"> <option>-----------------------</option> {% for func_dict in showlist.get_actions %} <option value="{{ func_dict.name }}">{{ func_dict.desc }}</option> {% endfor %} </select> <input type="submit" class="btn btn-warning " style="vertical-align: -8px"> <table class="table table-bordered table-striped action1 "> <thead> <tr> {% for item in showlist.get_header %} <td>{{ item }}</td> {% endfor %} </tr> </thead> <tbody> {% for data in showlist.get_body %} <tr> {% for foo in data %} <td>{{ foo }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </div> </form> </div> <div> <nav aria-label="..."> <ul class="pagination"> {{ showlist.pagination.page_html|safe }} </ul> </nav> </div> </div> <div class="col-md-3"> <div class="filter_region"> <div class="alert-warning text-center">FILTER</div> {% for key,val in showlist.get_filter_links.items %} <div class="panel panel-warning"> <div class="panel-heading">By{{ key|upper }}</div> <div class="panel-body"> {% for link in val %} <p>{{ link|safe }}</p> {% endfor %} </div> </div> {% endfor %} </div> </div> </div> </div> </body> </html>
pop
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h1>POP</h1> <script> window.opener.show_option("{{ pop_back_id }}",'{{ pk }}','{{ text }}'); window.close(); </script> </body> </html>
分页
fromdjango.conf.urlsimporturl fromdjango.shortcutsimportredirect,render fromdjango.urlsimportreverse fromdjango.utils.safestringimportmark_safe#渲染成html页面 fromstark.utils.pageimportPagination fromdjango.db.modelsimportQ ''' 封装分页相关数据 :paramcurrent_page:当前页 :paramall_count:数据库中的数据总条数 :paramper_page_num:每页显示的数据条数 :parambase_url:分页中显示的URL前缀 :parampager_count:最多显示的页码个数 ''' classShowlist(object): def__init__(self,conf_obj,queryset,request):#把配置类对象拿过来,request:从哪里过来的请求,queryset:就是下面showlist传进来的值 self.conf_obj=conf_obj self.queryset=queryset self.request=request #分页 current_page=self.request.GET.get("page") pagination=Pagination(current_page,self.queryset.count(),self.request.GET,per_page_num=2) self.pagination=pagination self.page_queryset=self.queryset[self.pagination.start:self.pagination.end] defget_header(self): #处理表头 #header_list=["名称","价格","出版社"] header_list=[] forfield_or_funcinself.conf_obj.get_new_list_display():#["title","price","publish",delete_col] ifisinstance(field_or_func,str): iffield_or_func=="__str__": val=self.conf_obj.model._meta.model_name.upper() else: field_obj=self.conf_obj.model._meta.get_field(field_or_func) val=field_obj.verbose_name#表头的字段如果用户设置了就显示中文 else: val=field_or_func(self.conf_obj,is_header=True) header_list.append(val) returnheader_list defget_body(self): #处理表单数据 data_list=[] forobjinself.page_queryset:#[obj1,obj2,obj3] temp=[] forfield_or_funcinself.conf_obj.get_new_list_display():#list_display=["title","price","publish",delete_col] ifisinstance(field_or_func,str): val=getattr(obj,field_or_func) iffield_or_funcinself.conf_obj.list_display_links: val=mark_safe("<ahref='%s'>%s</a>"%(self.conf_obj.get_reverse_url("change",obj),val)) else: val=field_or_func(self.conf_obj,obj) temp.append(val) data_list.append(temp) print(data_list) returndata_list #action批量处理 defget_actions(self): temp=[] forfuncinself.conf_obj.actions:#[patch_delete,] temp.append({ "name":func.__name__,#拿到是函数名 "desc":func.desc#拿到中文翻译 }) returntemp#[{"name":"patch_delete","desc":"批量删除"},] classModelStark():#默认配置类对象 def__init__(self,model): self.model=model self.model_name=self.model._meta.model_name self.app_label=self.model._meta.app_label self.app_model_name=(self.app_label,self.model_name) self.key_word=""#search操作设置为空 list_display=["__str__"] list_display_links=[]#默认的进入编辑, model_form_class=[]#默认的错误提示英文 search_fields=[]#模糊搜索框 actions=[]#批量初始化 #方式1 #反向解析出增删改查的url ##删除url #defget_delete_url(self,obj): #url_name="%s_%s_delete"%self.app_model_name #_url=reverse(url_name,args=(obj.pk,)) # #return_url # ##编辑url #defget_change_url(self,obj): #url_name="%s_%s_change"%self.app_model_name #_url=reverse(url_name,args=(obj.pk,)) # #return_url # # ##查看url #defget_list_url(self): #url_name="%s_%s_list"%self.app_model_name #_url=reverse(url_name) # #return_url # ##添加url #defget_add_url(self,obj): #url_name="%s_%s_add"%self.app_model_name #_url=reverse(url_name,args=(obj.pk,)) # #return_url # # #方式2反向解析 defget_reverse_url(self,type,obj=None):#obj默认为空 url_name="%s_%s_%s"%(self.app_label,self.model_name,type)#拼接出地址 ifobj: _url=reverse(url_name,args=(obj.pk,))#把地址传进来,还有有的url是动态的我们可以用一个元祖,把唯一id传进来 else: _url=reverse(url_name)#如果没有动态的,直接拼接地址 return_url #选择,删除,编辑按钮 defdelete_col(self,obj=None,is_header=False): ifis_header: return"删除" returnmark_safe("<ahref='%s'>删除</a>"%self.get_reverse_url("delete",obj)) defedit_col(self,obj=None,is_header=False): ifis_header: print(is_header) return"编辑" returnmark_safe("<ahref='%s'>编辑</a>"%(self.get_reverse_url("change",obj))) defcheck_col(self,obj=None,is_header=False): ifis_header: return"选择" returnmark_safe("<inputtype='checkbox'name='selected_action'value='%s'>"%obj.pk) defget_new_list_display(self):#把上面的放在一个字典里面 new_list_display=[] new_list_display.extend(self.list_display) ifnotself.list_display_links:#如果没有自定义的就用默认编辑 new_list_display.append(ModelStark.edit_col) new_list_display.append(ModelStark.delete_col) new_list_display.insert(0,ModelStark.check_col) returnnew_list_display #search搜索框 defsearch_filter(self,request,queryset): #search操作 key_word=request.GET.get("q")#拿到搜索框值 print(self.search_fields)#["title","price"] self.key_word=""#判断搜索框里面有没有值 ifkey_word: self.key_word=key_word#如果有把值赋给默认的 #调用q的另外的一个方法拿到值,不然我们普通循环拿到是字符串 search_condition=Q()#定义一个q search_condition.connector="or"#拿到的值是一个或的关系 forfieldinself.search_fields: search_condition.children.append((field+"__icontains",key_word))#field+"__icontains"里面包含有key_word有没 queryset=queryset.filter(search_condition) returnqueryset deflist_view(self,request): """ data_list=[ ["书",122], ] :paramrequest: :return: """ #action批量处理操作 #action操作 ifrequest.method=="POST": actions=request.POST.get("action")#拿到选择的方法名 pk_list=request.POST.getlist("selected_action")#通过getlist拿到所有的id列表 queryset=self.model.objects.filter(pk__in=pk_list)#筛选选择的那些id func1=getattr(self,actions)#通过方法名拿到对应的方法 func1(request,queryset)#把值传给app01下的stark看选择的是哪个 #用户访问的模型表:self.model print("self.model:",self.model) queryset=self.model.objects.all() print("self.list_display",self.list_display)#["nid","title","price","publish"] #处理表头 #search操作 queryset=self.search_filter(request,queryset)#赋值给queryset,然后下面拿到的就是新的 showlist=Showlist(self,queryset,request)#Showlist封装成一个类,前端可以通过showlist点方法 #获取添加url add_url=self.get_reverse_url("add") returnrender(request,"stark/list_view.html",locals()) defget_model_form_class(self):#把自定义的提示中文和modelForm封装成函数 ifself.model_form_class:#如果有自定义的提示中文 returnself.model_form_class else: fromdjangoimportforms classModelFormDemo(forms.ModelForm):#帮我们把model字段都转换form里面的字段 classMeta: model=self.model fields="__all__" returnModelFormDemo defadd_view(self,request): """ ifGET请求: GET请求: form=BookModelForm() form:渲染 ifPOST请求: form=BookModelForm(request.POST) form.is_valid() form.save()#添加数据create :paramrequest: :return: """ ModelFormDemo=self.get_model_form_class()#验证get_model_form_class拿到 ifrequest.method=="GET": form=ModelFormDemo() returnrender(request,"stark/add_view.html",locals())#locals就是相当于一个元祖传值 else: form=ModelFormDemo(request.POST) ifform.is_valid():#做校验 form.save()#这个的save相当于create returnredirect(self.get_reverse_url("list")) else: returnrender(request,"stark/add_view.html",locals()) defchange_view(self,request,id): """ edit_book=Book.objects.get(pk=id) GET: form=BookModelForm(instance=edit_book) form:渲染 POST: form=BookModelForm(request.POST,instance=edit_book) form.is_valid form.save()#更新数据update :paramrequest: :paramid: :return: """ ModelFormDemo=self.get_model_form_class() edit_obj=self.model.objects.get(pk=id) ifrequest.method=="GET": form=ModelFormDemo(instance=edit_obj) returnrender(request,"stark/change_view.html",locals()) else: form=ModelFormDemo(data=request.POST,instance=edit_obj)#instance方法就是决定了是更新还是添加,有就是更新 ifform.is_valid():#做校验 form.save()#这里相当于create returnredirect(self.get_reverse_url("list"))#返回list else: returnrender(request,"stark/change_view.html",locals()) defdelete_view(self,request,id): ifrequest.method=="POST": self.model.objects.get(pk=id).delete() returnredirect(self.get_reverse_url("list")) list_url=self.get_reverse_url("list") returnrender(request,"stark/delete_view.html",locals()) defget_urls(self): temp=[ url("^$",self.list_view,name="%s_%s_list"%(self.app_model_name)),#取别名 url("^add/$",self.add_view,name="%s_%s_add"%(self.app_model_name)), url("^(\d+)/change/$",self.change_view,name="%s_%s_change"%(self.app_model_name)), url("^(\d+)/delete/$",self.delete_view,name="%s_%s_delete"%(self.app_model_name)), ] returntemp @property defurls(self): returnself.get_urls(),None,None classStarkSite(object): def__init__(self,name='admin'): self._registry={} defregister(self,model,admin_class=None,**options): ifnotadmin_class: admin_class=ModelStark#配置类 self._registry[model]=admin_class(model) #{Book:BookConfig(Book),Publish:ModelAdmin(Publish)} defget_urls(self): temp=[ ] formodel_class,config_objinself._registry.items(): print("===>",model_class,config_obj) model_name=model_class._meta.model_name app_label=model_class._meta.app_label print("===>",app_label,model_name) temp.append(url(r'^%s/%s/'%(app_label,model_name),config_obj.urls)) ''' 创建url: url("app01/book/$",self.list_view,name="app01_book_list"), url("app01/book/add$",self.add_view,name="app01_book_add"), url("app01/book/(\d+)/change/$",self.change_view), url("app01/book/(\d+)/delete/$",self.delete_view), url("app01/publish/$",self.list_view,name="app01_publish_list"), url("app01/publish/add$",self.add_view,name="app01_publish_add"), url("app01/publish/(\d+)/change/$",self.change_view), url("app01/publish/(\d+)/delete/$",self.delete_view), ''' returntemp @property defurls(self): returnself.get_urls(),None,None site=StarkSite()