一、分页
1、引入自定义分页组件
在/stark目录下创建utils工具包目录,复制page.py到该目录下,文件中有之前自定义的分页组件。
class Pagination(object):def __init__(self, current_page, all_count, base_url, params, per_page_num&#61;8, pager_count&#61;11, ):"""封装分页相关数据:param current_page: 当前页:param all_count: 数据库中的数据总条数:param per_page_num: 每页显示的数据条数:param base_url: 分页中显示的URL前缀:param pager_count: 最多显示的页码个数"""try:current_page &#61; int(current_page)except Exception as e:current_page &#61; 1if current_page <1:current_page &#61; 1self.current_page &#61; current_pageself.all_count &#61; all_countself.per_page_num &#61; per_page_numself.base_url &#61; base_url# 总页码all_pager, tmp &#61; divmod(all_count, per_page_num)if tmp:all_pager &#43;&#61; 1self.all_pager &#61; all_pagerself.pager_count &#61; pager_count # 最多显示页码数self.pager_count_half &#61; int((pager_count - 1) / 2)import copyparams &#61; copy.deepcopy(params)params._mutable &#61; Trueself.params &#61; params # self.params : {"page":77,"title":"python","nid":1}
&#64;propertydef start(self):return (self.current_page - 1) * self.per_page_num&#64;propertydef end(self):return self.current_page * self.per_page_numdef page_html(self):# 如果总页码 <11个&#xff1a;if self.all_pager <&#61; self.pager_count:pager_start &#61; 1pager_end &#61; self.all_pager &#43; 1# 总页码 > 11else:# 当前页如果<&#61;页面上最多显示(11-1)/2个页码if self.current_page <&#61; self.pager_count_half:pager_start &#61; 1pager_end &#61; self.pager_count &#43; 1# 当前页大于5else:# 页码翻到最后if (self.current_page &#43; self.pager_count_half) > self.all_pager:pager_start &#61; self.all_pager - self.pager_count &#43; 1pager_end &#61; self.all_pager &#43; 1else:pager_start &#61; self.current_page - self.pager_count_halfpager_end &#61; self.current_page &#43; self.pager_count_half &#43; 1page_html_list &#61; []self.params["page"] &#61; 1first_page &#61; &#39;
self.params["page"] &#61; i # {"page":72,"title":"python","nid":1}if i &#61;&#61; self.current_page:temp &#61; &#39;
2、整合展示数据showlist类实现代码解耦
将list_view函数中的构建表头代码挪移到ShowList类的get_header函数下&#xff0c;将将list_view函数中的构建表单代码挪移到ShowList类的get_body函数下。
/stark/serivce/stark.py:
class ShowList(object):"""展示页面类"""def __init__(self, config, data_list):self.config &#61; config # 接收传递过来的配置类对象self.data_list &#61; data_list # 接收传递过来的当前表的所有对象def get_header(self):"""构建表头"""header_list &#61; []print("header", self.config.new_list_display()) # [checkbox ,"__str__", edit ,deletes]for field in self.config.new_list_display():if callable(field):# 如果是函数val &#61; field(self, header&#61;True)header_list.append(val)else:# 如果是字符串if field &#61;&#61; "__str__":header_list.append(self.config.model._meta.model_name.upper()) # 当前模型表名else:# 如果不是"__str__"# header_list.append(field)val &#61; self.config.model._meta.get_field(field).verbose_nameheader_list.append(val)
return header_listdef get_body(self):"""构建表单数据"""new_data_list &#61; []for obj in self.data_list:temp &#61; []for field in self.config.new_list_display(): # ["__str__", ] ["pk","name","age",edit]if callable(field):val &#61; field(self.config, obj)else:val &#61; getattr(obj, field)if field in self.config.list_display_links:# _url &#61; reverse("%s_%s_change" % (app_label, model_name), args&#61;(obj.pk,))_url &#61; self.config.get_change_url(obj)val &#61; mark_safe("%s" % (_url, val))temp.append(val)new_data_list.append(temp)
return new_data_listclass ModelStark(object):"""代码省略"""def list_view(self, request):data_list &#61; self.model.objects.all() # 拿到对应表所有的对象show_list &#61; ShowList(self, data_list) # 传入self&#xff0c;即将当前ModelStark的实例对象传给ShowList
header_list &#61; show_list.get_header()
new_data_list &#61; show_list.get_body()# 构建一个查看urladd_url &#61; self.get_add_url()return render(request, "list_view.html", locals())
&#xff08;1&#xff09;在list_view函数下执行ShowList实例化&#xff0c;在实例化时传入&#xff1a;
self:即当前ModelStark的实例对象&#xff1b;data_list&#xff1a;对应表所有的对象。
&#xff08;2&#xff09;在新的类ShowList通过__init__方法来接收者两个参数&#xff1a;
class ShowList(object):"""展示页面类"""def __init__(self, config, data_list):self.config &#61; config # 接收传递过来的配置类对象self.data_list &#61; data_list # 接收传递过来的当前表的所有对象
&#xff08;3&#xff09;给模板传递正确的数据
由于模板接收的数据是header_list和new_data_list。需要给get_header和get_body函数添加返回值。
同时在list_view中构建header_list和new_data_list变量&#xff1a;
show_list &#61; ShowList(self, data_list) # 传入self&#xff0c;即将当前ModelStark的实例对象传给ShowList
header_list &#61; show_list.get_header()
new_data_list &#61; show_list.get_body()
3、给查看页码添加分页
&#xff08;1&#xff09;service/stark.py:
from stark.utils.page import Paginationclass ShowList(object):"""展示页面类"""def __init__(self, config, data_list, request):self.config &#61; config # 接收传递过来的配置类对象self.data_list &#61; data_list # 接收传递过来的当前表的所有对象self.request &#61; request# 分页data_count &#61; self.data_list.count()current_page &#61; int(self.request.GET.get("page", 1)) # 默认是第一页base_path &#61; self.request.pathself.pagination &#61; Pagination(current_page, data_count, base_path, self.request.GET, per_page_num&#61;1, pager_count&#61;11,)self.page_data &#61; self.data_list[self.pagination.start:self.pagination.end]"""代码省略"""class ModelStark(object):"""代码省略"""def list_view(self, request):data_list &#61; self.model.objects.all() # 拿到对应表所有的对象show_list &#61; ShowList(self, data_list, request) # 传入self&#xff0c;即将当前ModelStark的实例对象传给ShowListheader_list &#61; show_list.get_header()new_data_list &#61; show_list.get_body()# 构建一个查看urladd_url &#61; self.get_add_url()print("add_url", add_url)return render(request, "list_view.html", locals())
&#xff08;1&#xff09;list_view函数中创建ShowList示例时多传入了一个request参数。ShowList拿到request后获取GET请求数据和请求路径&#xff1a;
class ShowList(object):"""展示页面类"""def __init__(self, config, data_list, request):self.config &#61; config # 接收传递过来的配置类对象self.data_list &#61; data_list # 接收传递过来的当前表的所有对象self.request &#61; request #
&#xff08;2&#xff09;实例化pagination&#xff0c;获取页码数据
引入自定义分页组件&#xff0c;将参数传入完成pagination实例化。获取当前页码数据&#xff1a;
class ShowList(object):"""展示页面类"""def __init__(self, config, data_list, request):&#39;&#39;&#39;代码省略&#39;&#39;&#39;self.pagination &#61; Pagination(current_page, data_count, base_path, self.request.GET, per_page_num&#61;1, pager_count&#61;11,)print("data_list", self.data_list) # data_list
&#xff08;3&#xff09;list_view.html添加分页
&#xff08;4&#xff09;显示效果如下&#xff1a; 输入查询内容后&#xff0c;点击搜索按钮&#xff0c;发送的get请求如下所示&#xff1a; # -*- coding:utf-8 -*- filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果需要执行更复杂的查询&#xff08;例如OR 语句&#xff09;可以使用Q对象。可以组合& 和| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时&#xff0c;Q 对象可以使用~ 操作符取反&#xff0c;这允许组合正常的查询和取反(NOT) 查询。 在这里由于需要循环self.search_fields&#xff0c;且拿到的都是一个个字符串。所以需要使用Q对象实例化的用法&#xff1a; Q查询特殊用法应用&#xff1a; 模糊查询应用&#xff1a;search_field&#43;"__contains" 查询效果&#xff1a; 提交查询后相当于获取了一个新的页面&#xff0c;要显示搜索的字段&#xff0c;必须获取该字段并传到新页面中。 这里需要注意show_list这个变量&#xff0c;在ModelStark类中list_view实例方法中&#xff0c;实例化ShowList类时&#xff0c;传递了self&#xff0c;这个self是ModelStark的实例对象&#xff0c;而这个实例对象由ShowList用self.config接收。因此show_list是ShowList的实例对象&#xff0c;具备config属性&#xff0c;show_list.config就是ModelStark的实例对象&#xff0c;具备key_word实例属性。 显示效果&#xff1a; 如果没有输入任何内容直接搜索&#xff0c;搜索框会显示一个None&#xff0c;如果要只显示为空&#xff0c;需要在request.GET.get("q")做如下调整&#xff1a; 在list_view.html中先通过if判断show_list.config.search_fields是否有值&#xff0c;有值则显示搜索框&#xff0c;否则不显示。 在自定义配置类注释掉search_fields字段。 app01/stark.py&#xff1a; 页面显示&#xff1a; app01/admin.py: 注意在这里可以通过patch_init.short_description设置批量操作中文名称。 批量处理前&#xff1a; 批量处理后&#xff1a; 注意页面中有两个表单&#xff0c;一个是搜索框的表单&#xff0c;另一个则是包含了aciton、表格、分页。 页面显示效果如下所示&#xff1a; app01/stark.py: /stark/service/stark.py: 在ModelStark类中默认actions&#61; []&#xff0c;因此在中实例化ShowList时&#xff0c;通过self将actions传递到ShowList类对象&#xff0c;以self.config.actions拿到配置好的函数对象列表交给get_action_list函数处理。 在get_action_list中循环处理函数对象列表&#xff0c;通过函数对象.__name__方式拿到函数名&#xff1b;通过函数对象.short_description拿到描述别名。以字典的形式保存在列表中返回给show_list对象交给页面进行渲染。 show_list.get_action_list拿到函数的返回值temp&#xff0c;循环拿到的item为一个个字典&#xff0c;键为name的是函数名&#xff0c;键为desc的是描述别名。 点选批量操作需要拿到当前操作对象的pk值&#xff0c;也需要判断哪些标签被点选提交。 在这里POST请求处理不需要返回值&#xff0c;批量初始化后&#xff0c;数据库已经更改&#xff0c;代码顺着下来紧接着就是查询拿到新的页面。 class BookConfig(ModelStark):list_display &#61; ["title", "price", "publishDate"]modelform_class &#61; BookModelFormsearch_fields &#61; [&#39;title&#39;, "price"]def patch_init(self, request, queryset):print(queryset)queryset.update(price&#61;123)patch_init.short_description &#61; "批量初始化"actions &#61; [patch_init]site.register(Book, BookConfig) 显示效果&#xff1a; 在new_actions实例方法中&#xff0c;首先可以通过ModelStark.patch_delete固定拿到默认需要添加的批量删除方法。其次ModelStark类中默认actions&#61;[]&#xff0c;因此在自定义配置类有配置actions时&#xff0c;self.actions拿到默认配置类配置的列表&#xff0c;如果没有配置拿到空列表。然后通过extend函数扩展列表返回所有批量操作函数。 ShowList实例化时&#xff0c;self.actions属性通过self.config.new_actions()拿到new_actions返回结果。然后在模板上就可以通过show_list.config.actions渲染所有的actions操作了。 显示效果&#xff1a; 1&#xff09;自定义配置类没有配置actions: 2&#xff09;自定义配置类配置了actions&#xff1a; 转:https://www.cnblogs.com/xiugeng/p/9515102.html数据列表
二、search查询
1、在查看页面添加搜索框
数据列表
2、查询匹配
__author__ &#61; &#39;Qiushi Huang&#39;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 Paginationclass ShowList(object):"""展示页面类"""def __init__(self, config, data_list, request):self.config &#61; config # 接收传递过来的配置类对象 ModelStark的实例对象self.data_list &#61; data_list # 接收传递过来的当前表的所有对象self.request &#61; request #
self.pagination &#61; Pagination(current_page, data_count, base_path, self.request.GET, per_page_num&#61;1, pager_count&#61;11,)print("data_list", self.data_list) # data_list
form.save()return redirect(self.get_list_url()) # 跳转到当前访问表的查看页面# &#xff08;精髓&#xff09;校验有错误返回页面&#xff0c;且包含了错误信息return render(request, "add_view.html", locals())form &#61; ModelFormDemo() # 实例化return render(request, "add_view.html", locals())def delete_view(self, request, id):url &#61; self.get_list_url()if request.method &#61;&#61; "POST":self.model.objects.filter(pk&#61;id).delete()return redirect(url)# self.model.objects.filter(pk&#61;id).delete()return render(request, "delete_view.html", locals())def change_view(self, request, id):"""编辑视图"""ModelFormDemo &#61; self.get_modelform_class()# 编辑对象edit_obj &#61; self.model.objects.filter(pk&#61;id).first()if request.method &#61;&#61; "POST":form &#61; ModelFormDemo(request.POST, instance&#61;edit_obj) # instance就是给这个记录更改为最新的数据if form.is_valid(): # 校验字段全部合格
form.save()return redirect(self.get_list_url()) # 跳转到当前访问表的查看页面# &#xff08;精髓&#xff09;校验有错误返回页面&#xff0c;且包含了错误信息return render(request, "add_view.html", locals())form &#61; ModelFormDemo(instance&#61;edit_obj) # 用instance放入编辑对象就有了编辑数据return render(request, "change_view.html", locals())def new_list_display(self):"""返回新的列表"""temp &#61; []temp.append(ModelStark.checkbox) # 在列表中放一个checkbox名字temp.extend(self.list_display) # 扩展进一个列表["pk","name","age"]if not self.list_display_links:# 如果没有值
temp.append(ModelStark.edit)# temp.append(ModelStark.edit) # edit函数名temp.append(ModelStark.deletes) # deletes函数名return temp # 返回新的列表def get_change_url(self,obj):model_name &#61; self.model._meta.model_nameapp_label &#61; self.model._meta.app_label_url &#61; reverse("%s_%s_change" % (app_label, model_name), args&#61;(obj.pk,))return _urldef get_delete_url(self, obj):model_name &#61; self.model._meta.model_nameapp_label &#61; self.model._meta.app_label_url &#61; reverse("%s_%s_delete" % (app_label, model_name), args&#61;(obj.pk,))return _urldef get_add_url(self):model_name &#61; self.model._meta.model_nameapp_label &#61; self.model._meta.app_label_url &#61; reverse("%s_%s_add" % (app_label, model_name))return _urldef get_list_url(self):model_name &#61; self.model._meta.model_nameapp_label &#61; self.model._meta.app_label_url &#61; reverse("%s_%s_list" % (app_label, model_name))return _urldef get_search_condition(self, request):key_word &#61; request.GET.get("q", "") # 取不到q则直接取空self.key_word &#61; key_wordfrom django.db.models import Qsearch_connection &#61; Q()if key_word: # 判断key_word是否为空search_connection.connector &#61; "or" # 查询条件设置为或for search_field in self.search_fields: # self.search_fields # [&#39;title&#39;, "price"]search_connection.children.append((search_field &#43; "__contains", key_word))return search_connectiondef list_view(self, request):# 获取search的Q对象search_condition &#61; self.get_search_condition(request)# 筛选当前表获取的数据data_list &#61; self.model.objects.all().filter(search_condition)# 获取showlist展示页面show_list &#61; ShowList(self, data_list, request)header_list &#61; show_list.get_header()new_data_list &#61; show_list.get_body()# 构建一个查看urladd_url &#61; self.get_add_url()print("add_url", add_url)return render(request, "list_view.html", locals())def get_urls_2(self):temp &#61; []# 用name取别名app名&#43;model名&#43;操作名可以保证别名不会重复model_name &#61; self.model._meta.model_nameapp_label &#61; self.model._meta.app_labeltemp.append(url(r"^add/", self.add_view, name&#61;"%s_%s_add" % (app_label, model_name)))temp.append(url(r"^(\d&#43;)/delete/", self.delete_view, name&#61;"%s_%s_delete" % (app_label, model_name)))temp.append(url(r"^(\d&#43;)/change/", self.change_view, name&#61;"%s_%s_change" % (app_label, model_name)))temp.append(url(r"^$", self.list_view, name&#61;"%s_%s_list" % (app_label, model_name)))return temp&#64;propertydef urls_2(self):return self.get_urls_2(), None, None # [], None, Noneclass StarkSite(object):"""site单例类"""def __init__(self):self._registry &#61; {}def register(self, model, stark_class&#61;None, **options):"""注册"""if not stark_class:# 如果注册的时候没有自定义配置类,执行stark_class &#61; ModelStark # 配置类# 将配置类对象加到_registry字典中&#xff0c;键为模型类self._registry[model] &#61; stark_class(model, self) # _registry&#61;{&#39;model&#39;:admin_class(model)}def get_urls(self):"""构造一层url"""temp &#61; []for model, stark_class_obj in self._registry.items():# model:一个模型表# stark_class_obj:当前模型表相应的配置类对象
model_name &#61; model._meta.model_nameapp_label &#61; model._meta.app_label# 分发增删改查temp.append(url(r"^%s/%s/" % (app_label, model_name), stark_class_obj.urls_2))"""path(&#39;app01/userinfo/&#39;,UserConfig(Userinfo,site).urls2),path(&#39;app01/book/&#39;,ModelStark(Book,site).urls2),"""return temp&#64;propertydef urls(self):return self.get_urls(), None, Nonesite &#61; StarkSite() # 单例对象 &#xff08;1&#xff09;Q查询
from .models import *def test(request):from django.db.models import Q# Q查询普通写法&#xff1a;ret &#61; Book.objects.all().filter(Q(title&#61;"go")|Q(price&#61;103))print("ret", ret) # ret
class ModelStark(object):def list_view(self, request):key_word &#61; request.GET.get("q")from django.db.models import Qsearch_connection &#61; Q()search_connection.connector &#61; "or" # 查询条件设置为或for search_field in self.search_fields: # self.search_fields # [&#39;title&#39;, "price"]search_connection.children.append((search_field, key_word))data_list &#61; self.model.objects.all().filter(search_connection)# 获取showlist展示页面show_list &#61; ShowList(self, data_list, request)header_list &#61; show_list.get_header()new_data_list &#61; show_list.get_body()# 构建一个查看urladd_url &#61; self.get_add_url()print("add_url", add_url)return render(request, "list_view.html", locals())
&#xff08;2&#xff09;基于双下划线的模糊查询
# __startwith: 以...开头
ret &#61; Book.objects.filter(title__startswith&#61;"py")
print(ret) #
ret &#61; Book.objects.filter(title__contains&#61;"h")
print(ret) # class ModelStark(object):def list_view(self, request):key_word &#61; request.GET.get("q")from django.db.models import Qsearch_connection &#61; Q()if key_word: # 判断key_word是否为空search_connection.connector &#61; "or" # 查询条件设置为或for search_field in self.search_fields: # self.search_fields # [&#39;title&#39;, "price"]search_connection.children.append((search_field &#43; "__contains", key_word))# 获取当前表所有数据data_list &#61; self.model.objects.all().filter(search_connection)
&#xff08;3&#xff09;在实例方法中封装模糊查询
class ModelStark(object):def get_search_condition(self, request):key_word &#61; request.GET.get("q")from django.db.models import Qsearch_connection &#61; Q()if key_word: # 判断key_word是否为空search_connection.connector &#61; "or" # 查询条件设置为或for search_field in self.search_fields: # self.search_fields # [&#39;title&#39;, "price"]search_connection.children.append((search_field &#43; "__contains", key_word))return search_connectiondef list_view(self, request):# 获取search的Q对象search_condition &#61; self.get_search_condition(request)# 筛选当前表获取的数据data_list &#61; self.model.objects.all().filter(search_condition)# 获取showlist展示页面show_list &#61; ShowList(self, data_list, request)header_list &#61; show_list.get_header()new_data_list &#61; show_list.get_body()# 构建一个查看urladd_url &#61; self.get_add_url()print("add_url", add_url)return render(request, "list_view.html", locals())
&#xff08;4&#xff09;查询提交后&#xff0c;查询框依旧显示搜索的字段
class ModelStark(object):def get_search_condition(self, request):key_word &#61; request.GET.get("q", "") # 取不到q则直接取空self.key_word &#61; key_wordfrom django.db.models import Qsearch_connection &#61; Q()if key_word: # 判断key_word是否为空search_connection.connector &#61; "or" # 查询条件设置为或for search_field in self.search_fields: # self.search_fields # [&#39;title&#39;, "price"]search_connection.children.append((search_field &#43; "__contains", key_word))return search_connection
3、自定义配置类中配置search_fields则显示搜索框&#xff0c;否则不显示
数据列表
class BookConfig(ModelStark):list_display &#61; ["title", "price", "publishDate"]modelform_class &#61; BookModelForm# search_fields &#61; [&#39;title&#39;, "price"]site.register(Book, BookConfig)
三、actions——批量处理
1、admin组件实现actions批量处理
from django.contrib import admin
from .models import Bookclass BookConfig(admin.ModelAdmin):list_display &#61; ["title", "price"]def patch_init(self, request, queryset):print("queryset", queryset)# queryset 2、在list_view.html中添加action选择框&#xff0c;重构form表单
3、自定义配置actions
&#xff08;1&#xff09;构建自定义配置类actions的函数
class BookConfig(ModelStark):list_display &#61; ["title", "price", "publishDate"]modelform_class &#61; BookModelFormsearch_fields &#61; [&#39;title&#39;, "price"]def patch_init(self, request, queryset):print(queryset)patch_init.short_description &#61; "批量初始化"actions &#61; [patch_init]site.register(Book, BookConfig)
&#xff08;2&#xff09;处理actions批量操作函数
class ShowList(object):"""展示页面类"""def __init__(self, config, data_list, request):self.config &#61; config # 接收传递过来的配置类对象 ModelStark的实例对象self.data_list &#61; data_list # 接收传递过来的当前表的所有对象self.request &#61; request #
&#xff08;3&#xff09;进一步构建批量操作表单
{% csrf_token %}
&#xff08;4&#xff09;显示效果
3、实现点选提交
&#xff08;1&#xff09;重构checkbox标签
class ModelStark(object):"""代码省略"""def checkbox(self, obj&#61;None, header&#61;False):"""复选框"""if header:# 如果是表头显示操作return mark_safe("")return mark_safe("" % obj.pk)
&#xff08;2&#xff09;list_view处理post请求
class ModelStark(object):def list_view(self, request):if request.method &#61;&#61; "POST": # actionprint("POST:", request.POST)action &#61; request.POST.get("action")selected_pk &#61; request.POST.getlist("selected_pk") # 拿到列表# 反射# self这里是配置类BookConfig&#xff0c;要在类中找到对应的函数action_func &#61; getattr(self, action) # patch_init# 拿到选中状态的pk值对象queryset &#61; self.model.objects.filter(pk__in&#61;selected_pk) #
&#xff08;3&#xff09;配置校验
4、添加admin批量操作自带的delete功能
class ShowList(object):def __init__(self, config, data_list, request):self.config &#61; config # 接收传递过来的配置类对象 ModelStark的实例对象self.data_list &#61; data_list # 接收传递过来的当前表的所有对象self.request &#61; request #