一、分页

1、引入自定义分页组件

  在/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)

/stark/utils/page.py

2、整合展示数据showlist类实现代码解耦

  将list_view函数中的构建表头代码挪移到ShowList类的get_header函数下,将将list_view函数中的构建表单代码挪移到ShowList类的get_body函数下。

/stark/serivce/stark.py:

class ShowList(object):
"""展示页面类"""
def __init__(self, config, data_list):
self.config = config # 接收传递过来的配置类对象
self.data_list = data_list # 接收传递过来的当前表的所有对象 def get_header(self):
"""构建表头"""
header_list = []
print("header", self.config.new_list_display()) # [checkbox ,"__str__", edit ,deletes] for field in self.config.new_list_display(): if callable(field):
# 如果是函数
val = field(self, header=True)
header_list.append(val) else:
# 如果是字符串
if field == "__str__":
header_list.append(self.config.model._meta.model_name.upper()) # 当前模型表名
else:
# 如果不是"__str__"
# header_list.append(field)
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:
temp = []
for field in self.config.new_list_display(): # ["__str__", ] ["pk","name","age",edit]
if callable(field):
val = field(self.config, obj)
else:
val = getattr(obj, field)
if field in self.config.list_display_links:
# _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,))
_url = self.config.get_change_url(obj) val = mark_safe("<a href='%s'>%s</a>" % (_url, val))
temp.append(val)
new_data_list.append(temp)
return new_data_list class ModelStark(object):
"""代码省略"""
def list_view(self, request):
data_list = self.model.objects.all() # 拿到对应表所有的对象
show_list = ShowList(self, data_list) # 传入self,即将当前ModelStark的实例对象传给ShowList
header_list = show_list.get_header()
new_data_list = show_list.get_body()
# 构建一个查看url
add_url = self.get_add_url()
return render(request, "list_view.html", locals())

(1)在list_view函数下执行ShowList实例化,在实例化时传入:

  self:即当前ModelStark的实例对象;data_list:对应表所有的对象。

(2)在新的类ShowList通过__init__方法来接收者两个参数:

class ShowList(object):
"""展示页面类"""
def __init__(self, config, data_list):
self.config = config # 接收传递过来的配置类对象
self.data_list = data_list # 接收传递过来的当前表的所有对象

(3)给模板传递正确的数据

  由于模板接收的数据是header_list和new_data_list。需要给get_header和get_body函数添加返回值。

  同时在list_view中构建header_list和new_data_list变量:

show_list = ShowList(self, data_list)  # 传入self,即将当前ModelStark的实例对象传给ShowList
header_list = show_list.get_header()
new_data_list = show_list.get_body()

3、给查看页码添加分页

(1)service/stark.py:

from stark.utils.page import Pagination

class ShowList(object):
"""展示页面类"""
def __init__(self, config, data_list, request):
self.config = config # 接收传递过来的配置类对象
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]
"""代码省略""" class ModelStark(object):
"""代码省略"""
def list_view(self, request):
data_list = self.model.objects.all() # 拿到对应表所有的对象
show_list = ShowList(self, data_list, request) # 传入self,即将当前ModelStark的实例对象传给ShowList
header_list = show_list.get_header()
new_data_list = show_list.get_body()
# 构建一个查看url
add_url = self.get_add_url()
print("add_url", add_url)
return render(request, "list_view.html", locals())

(1)list_view函数中创建ShowList示例时多传入了一个request参数。ShowList拿到request后获取GET请求数据和请求路径:

class ShowList(object):
"""展示页面类"""
def __init__(self, config, data_list, request):
self.config = config # 接收传递过来的配置类对象
self.data_list = data_list # 接收传递过来的当前表的所有对象
self.request = request # <WSGIRequest: GET '/stark/app01/book/?page=2'>
# 分页
data_count = self.data_list.count()
current_page = int(self.request.GET.get("page", 1)) # 默认是第一页
base_path = self.request.path # /stark/app01/book/

(2)实例化pagination,获取页码数据

  引入自定义分页组件,将参数传入完成pagination实例化。获取当前页码数据:

class ShowList(object):
"""展示页面类"""
def __init__(self, config, data_list, request):
'''代码省略'''
self.pagination = Pagination(current_page, data_count, base_path, self.request.GET, per_page_num=1, pager_count=11,)
print("data_list", self.data_list) # data_list <QuerySet [<Book: python葵花宝典>, <Book: go>, <Book: java>]>
self.page_data = self.data_list[self.pagination.start:self.pagination.end]
print("page_data", self.page_data) # page_data <QuerySet [<Book: python葵花宝典>]> '''代码省略'''
def get_body(self):
"""构建表单数据"""
new_data_list = []
# for obj in self.data_list:
for obj in self.page_data: # 当前页面的数据
'''代码省略'''

(3)list_view.html添加分页

<body>
<h4>数据列表</h4>
<div class="container">
<div class="row">
<div class="col-md-9"....代码省略..>
<nav>
<ul class="pagination">
{{ show_list.pagination.page_html|safe }}
</ul>
</nav>
</div>
</div>

(4)显示效果如下:

  

二、search查询

1、在查看页面添加搜索框

<h4>数据列表</h4>
<div class="container">
<div class="row">
<div class="col-md-9">
<a href="{{ add_url }}" class="btn btn-primary">添加数据</a>
<form action="" class="pull-right">
<input type="text" name="q">
<button>搜索</button>
</form>
<table class="table table-bordered table-striped".....>
</div>
<nav....>
</div>
</div>

  输入查询内容后,点击搜索按钮,发送的get请求如下所示:

  

2、查询匹配

# -*- coding:utf-8 -*-
__author__ = 'Qiushi Huang' 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 # <WSGIRequest: GET '/stark/app01/book/?page=2'>
# 分页
data_count = self.data_list.count()
current_page = int(self.request.GET.get("page", 1)) # 默认是第一页
base_path = self.request.path # /stark/app01/book/ self.pagination = Pagination(current_page, data_count, base_path, self.request.GET, per_page_num=1, pager_count=11,)
print("data_list", self.data_list) # data_list <QuerySet [<Book: python葵花宝典>, <Book: go>, <Book: java>]>
self.page_data = self.data_list[self.pagination.start:self.pagination.end]
print("page_data", self.page_data) # page_data <QuerySet [<Book: python葵花宝典>]> def get_header(self):
"""构建表头"""
header_list = []
print("header", self.config.new_list_display()) # [checkbox ,"__str__", edit ,deletes] for field in self.config.new_list_display(): if callable(field):
# 如果是函数
val = field(self, header=True)
header_list.append(val) else:
# 如果是字符串
if field == "__str__":
header_list.append(self.config.model._meta.model_name.upper()) # 当前模型表名
else:
# 如果不是"__str__"
# header_list.append(field)
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:
for obj in self.page_data: # 当前页面的数据
temp = [] for field in self.config.new_list_display(): # ["__str__", ] ["pk","name","age",edit] if callable(field):
val = field(self.config, obj)
else:
val = getattr(obj, field)
if field in self.config.list_display_links:
# _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,))
_url = self.config.get_change_url(obj) val = mark_safe("<a href='%s'>%s</a>" % (_url, val)) temp.append(val) new_data_list.append(temp)
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 # 删除、编辑,复选框
def edit(self, obj=None, header=False):
"""编辑"""
if header:
# 如果是表头显示操作
return "操作" _url = self.get_change_url(obj)
return mark_safe("<a href='%s'>编辑</a>" % _url) def deletes(self, obj=None, header=False):
"""删除"""
if header:
# 如果是表头显示操作
return "操作" _url = self.get_delete_url(obj)
# return mark_safe("<a href='%s/change'>删除</a>" % obj.pk)
return mark_safe("<a href='%s/'>删除</a>" % _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 get_modelform_class(self):
"""用来获取modelform类"""
if not self.modelform_class:
# 如果没有值
from django.forms import ModelForm
from django.forms import widgets as wid class ModelFormDemo(ModelForm):
class Meta:
model = self.model
fields = "__all__" return ModelFormDemo
else:
# 如果有值说明在用户已经自己定制过了,直接取值
return self.modelform_class def add_view(self, request):
ModelFormDemo = self.get_modelform_class()
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()) form = ModelFormDemo() # 实例化
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) # self.model.objects.filter(pk=id).delete()
return render(request, "delete_view.html", locals()) def change_view(self, request, id):
"""编辑视图"""
ModelFormDemo = self.get_modelform_class()
# 编辑对象
edit_obj = self.model.objects.filter(pk=id).first() if request.method == "POST":
form = ModelFormDemo(request.POST, instance=edit_obj) # instance就是给这个记录更改为最新的数据
if form.is_valid(): # 校验字段全部合格
form.save()
return redirect(self.get_list_url()) # 跳转到当前访问表的查看页面 # (精髓)校验有错误返回页面,且包含了错误信息
return render(request, "add_view.html", locals()) form = ModelFormDemo(instance=edit_obj) # 用instance放入编辑对象就有了编辑数据 return render(request, "change_view.html", locals()) def new_list_display(self):
"""返回新的列表"""
temp = []
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 = self.model._meta.model_name
app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) return _url def get_delete_url(self, obj):
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 _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 get_search_condition(self, request):
key_word = request.GET.get("q", "") # 取不到q则直接取空
self.key_word = key_word
from django.db.models import Q
search_connection = Q()
if key_word: # 判断key_word是否为空
search_connection.connector = "or" # 查询条件设置为或
for search_field in self.search_fields: # self.search_fields # ['title', "price"]
search_connection.children.append((search_field + "__contains", key_word))
return search_connection def list_view(self, request):
# 获取search的Q对象
search_condition = self.get_search_condition(request)
# 筛选当前表获取的数据
data_list = self.model.objects.all().filter(search_condition) # 获取showlist展示页面
show_list = ShowList(self, data_list, request) header_list = show_list.get_header()
new_data_list = show_list.get_body() # 构建一个查看url
add_url = self.get_add_url()
print("add_url", add_url)
return render(request, "list_view.html", locals()) def get_urls_2(self):
temp = [] # 用name取别名app名+model名+操作名可以保证别名不会重复
model_name = self.model._meta.model_name
app_label = self.model._meta.app_label
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)))
temp.append(url(r"^$", self.list_view, name="%s_%s_list" % (app_label, model_name)))
return temp @property
def urls_2(self):
return self.get_urls_2(), None, None # [], None, None class StarkSite(object):
"""site单例类"""
def __init__(self):
self._registry = {} def register(self, model, stark_class=None, **options):
"""注册"""
if not stark_class:
# 如果注册的时候没有自定义配置类,执行
stark_class = ModelStark # 配置类 # 将配置类对象加到_registry字典中,键为模型类
self._registry[model] = stark_class(model, self) # _registry={'model':admin_class(model)} def get_urls(self):
"""构造一层url"""
temp = []
for model, stark_class_obj in self._registry.items():
# model:一个模型表
# stark_class_obj:当前模型表相应的配置类对象 model_name = model._meta.model_name
app_label = model._meta.app_label # 分发增删改查
temp.append(url(r"^%s/%s/" % (app_label, model_name), stark_class_obj.urls_2))
"""
path('app01/userinfo/',UserConfig(Userinfo,site).urls2),
path('app01/book/',ModelStark(Book,site).urls2),
""" return temp @property
def urls(self):
return self.get_urls(), None, None site = StarkSite() # 单例对象

stark/service/stark.py

(1)Q查询

  filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果需要执行更复杂的查询(例如OR 语句)可以使用Q对象。可以组合& 和|  操作符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可以使用~ 操作符取反,这允许组合正常的查询和取反(NOT) 查询。

  在这里由于需要循环self.search_fields,且拿到的都是一个个字符串。所以需要使用Q对象实例化的用法:

from .models import *

def test(request):
from django.db.models import Q
# Q查询普通写法:
ret = Book.objects.all().filter(Q(title="go")|Q(price=103))
print("ret", ret) # ret <QuerySet [<Book: go>]>
# Q查询特殊用法:
q = Q()
q.connectiion = "or"
q.children.append(("title", "go"))
q.children.append(("price", 103))
print("q", q) # q (AND: ('title', 'yuan'), ('price', 123))
return HttpResponse(ret, q)

  Q查询特殊用法应用:

class ModelStark(object):
def list_view(self, request):
key_word = request.GET.get("q") from django.db.models import Q
search_connection = Q()
search_connection.connector = "or" # 查询条件设置为或
for search_field in self.search_fields: # self.search_fields # ['title', "price"]
search_connection.children.append((search_field, key_word)) data_list = self.model.objects.all().filter(search_connection) # 获取showlist展示页面
show_list = ShowList(self, data_list, request)
header_list = show_list.get_header()
new_data_list = show_list.get_body()
# 构建一个查看url
add_url = self.get_add_url()
print("add_url", add_url)
return render(request, "list_view.html", locals())

(2)基于双下划线的模糊查询

# __startwith: 以...开头
ret = Book.objects.filter(title__startswith="py")
print(ret) # <QuerySet [<Book: python红宝书>]> # __contains:带有...字符
ret = Book.objects.filter(title__contains="h")
print(ret) # <QuerySet [<Book: python红宝书>, <Book: php宝典>]>

  模糊查询应用:search_field+"__contains"

class ModelStark(object):
def list_view(self, request):
key_word = request.GET.get("q")
from django.db.models import Q
search_connection = Q()
if key_word: # 判断key_word是否为空
search_connection.connector = "or" # 查询条件设置为或
for search_field in self.search_fields: # self.search_fields # ['title', "price"]
search_connection.children.append((search_field + "__contains", key_word)) # 获取当前表所有数据
data_list = self.model.objects.all().filter(search_connection)

  查询效果:

  

(3)在实例方法中封装模糊查询

class ModelStark(object):
def get_search_condition(self, request):
key_word = request.GET.get("q")
from django.db.models import Q
search_connection = Q()
if key_word: # 判断key_word是否为空
search_connection.connector = "or" # 查询条件设置为或
for search_field in self.search_fields: # self.search_fields # ['title', "price"]
search_connection.children.append((search_field + "__contains", key_word))
return search_connection def list_view(self, request):
# 获取search的Q对象
search_condition = self.get_search_condition(request)
# 筛选当前表获取的数据
data_list = self.model.objects.all().filter(search_condition) # 获取showlist展示页面
show_list = ShowList(self, data_list, request) header_list = show_list.get_header()
new_data_list = show_list.get_body() # 构建一个查看url
add_url = self.get_add_url()
print("add_url", add_url)
return render(request, "list_view.html", locals())

(4)查询提交后,查询框依旧显示搜索的字段

  提交查询后相当于获取了一个新的页面,要显示搜索的字段,必须获取该字段并传到新页面中。

<form action="" class="pull-right">
<input type="text" name="q" value="{{ show_list.config.key_word }}">
<button>搜索</button>
</form>

  这里需要注意show_list这个变量,在ModelStark类中list_view实例方法中,实例化ShowList类时,传递了self,这个self是ModelStark的实例对象,而这个实例对象由ShowList用self.config接收。因此show_list是ShowList的实例对象,具备config属性,show_list.config就是ModelStark的实例对象,具备key_word实例属性。

  显示效果:

  

  如果没有输入任何内容直接搜索,搜索框会显示一个None,如果要只显示为空,需要在request.GET.get("q")做如下调整:

class ModelStark(object):
def get_search_condition(self, request):
key_word = request.GET.get("q", "") # 取不到q则直接取空
self.key_word = key_word
from django.db.models import Q
search_connection = Q()
if key_word: # 判断key_word是否为空
search_connection.connector = "or" # 查询条件设置为或
for search_field in self.search_fields: # self.search_fields # ['title', "price"]
search_connection.children.append((search_field + "__contains", key_word))
return search_connection

3、自定义配置类中配置search_fields则显示搜索框,否则不显示

  在list_view.html中先通过if判断show_list.config.search_fields是否有值,有值则显示搜索框,否则不显示。

<h4>数据列表</h4>
<div class="container">
<div class="row">
<div class="col-md-9">
{# <a href="add/" class="btn btn-primary">添加数据</a> #}
<a href="{{ add_url }}" class="btn btn-primary">添加数据</a>
{% if show_list.config.search_fields %}
<form action="" class="pull-right">
<input type="text" name="q" value="{{ show_list.config.key_word }}">
<button>搜索</button>
</form>
{% endif %}
<table class="table table-bordered table-striped"......>
</div>
<nav>
<ul class="pagination">
{{ show_list.pagination.page_html|safe }}
</ul>
</nav>
</div>
</div>

  在自定义配置类注释掉search_fields字段。

app01/stark.py:

class BookConfig(ModelStark):
list_display = ["title", "price", "publishDate"]
modelform_class = BookModelForm
# search_fields = ['title', "price"] site.register(Book, BookConfig)

  页面显示:

  

三、actions——批量处理

1、admin组件实现actions批量处理

app01/admin.py:

from django.contrib import admin
from .models import Book class BookConfig(admin.ModelAdmin):
list_display = ["title", "price"] def patch_init(self, request, queryset):
print("queryset", queryset)
# queryset <QuerySet [<Book: java>, <Book: python葵花宝典>]>
queryset.update(price=100) patch_init.short_description = "批量初始化"
actions = [patch_init] admin.site.register(Book, BookConfig)

  注意在这里可以通过patch_init.short_description设置批量操作中文名称。

批量处理前:

  

批量处理后:

  

2、在list_view.html中添加action选择框,重构form表单

<div class="container">
<div class="row">
<div class="col-md-9">
{# <a href="add/" class="btn btn-primary">添加数据</a> #}
<a href="{{ add_url }}" class="btn btn-primary">添加数据</a>
{% if show_list.config.search_fields %}
<form action="" class="pull-right">
<input type="text" name="q" value="{{ show_list.config.key_word }}">
<button>搜索</button>
</form>
{% endif %}
<form action="">
<select name="action" id="" style="width: 200px; padding: 5px 8px; display: inline-block">
<option value="">xxxxx</option>
</select>
<button type="submit" class="btn-info">Go</button>
<table class="table table-bordered table-striped"......>
<nav.....>
</form>
</div>
</div>
</div>

  注意页面中有两个表单,一个是搜索框的表单,另一个则是包含了aciton、表格、分页。

  页面显示效果如下所示:

  

3、自定义配置actions

(1)构建自定义配置类actions的函数

app01/stark.py:

class BookConfig(ModelStark):
list_display = ["title", "price", "publishDate"]
modelform_class = BookModelForm
search_fields = ['title', "price"] def patch_init(self, request, queryset):
print(queryset) patch_init.short_description = "批量初始化"
actions = [patch_init] site.register(Book, BookConfig)

(2)处理actions批量操作函数

/stark/service/stark.py:

class ShowList(object):
"""展示页面类"""
def __init__(self, config, data_list, request):
self.config = config # 接收传递过来的配置类对象 ModelStark的实例对象
self.data_list = data_list # 接收传递过来的当前表的所有对象
self.request = request # <WSGIRequest: GET '/stark/app01/book/?page=2'>
# 分页
data_count = self.data_list.count()
current_page = int(self.request.GET.get("page", 1)) # 默认是第一页
base_path = self.request.path # /stark/app01/book/ self.pagination = Pagination(current_page, data_count, base_path, self.request.GET, per_page_num=3, pager_count=11,)
self.page_data = self.data_list[self.pagination.start:self.pagination.end] # actions
self.actions = self.config.actions # 拿到配置好的函数对象列表 [patch_init,] def get_action_list(self):
temp = []
for action in self.actions:
temp.append({
"name": action.__name__, # 函数.__name__:拿到函数名
"desc": action.short_description
}) # [{"name": "patch_init", "desc": "批量处理"}]
return temp
"""代码省略""" class ModelStark(object):
"""默认类,定制配置类"""
list_display = ["__str__",]
list_display_links = []
modelform_class = []
search_fields = []
actions = [] # 调用self.actions拿到的是函数
"""代码省略"""

  在ModelStark类中默认actions= [],因此在中实例化ShowList时,通过self将actions传递到ShowList类对象,以self.config.actions拿到配置好的函数对象列表交给get_action_list函数处理。

  在get_action_list中循环处理函数对象列表,通过函数对象.__name__方式拿到函数名;通过函数对象.short_description拿到描述别名。以字典的形式保存在列表中返回给show_list对象交给页面进行渲染。

(3)进一步构建批量操作表单

<form action="" method="post">
{% csrf_token %}
<select name="action" id="" style="width: 200px; padding: 5px 8px; display: inline-block">
<option value="">-----------</option>
{% for item in show_list.get_action_list %}
<option value="{{ item.name }}">{{ item.desc }}</option>
{% endfor %}
</select>
<button type="submit" class="btn-info">Go</button>
<table class="table table-bordered table-striped"......>
<nav>
<ul class="pagination">
{{ show_list.pagination.page_html|safe }}
</ul>
</nav>
</form>

  show_list.get_action_list拿到函数的返回值temp,循环拿到的item为一个个字典,键为name的是函数名,键为desc的是描述别名。

(4)显示效果

  

3、实现点选提交

(1)重构checkbox标签

  点选批量操作需要拿到当前操作对象的pk值,也需要判断哪些标签被点选提交。

class ModelStark(object):
"""代码省略"""
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)

(2)list_view处理post请求

class ModelStark(object):
def list_view(self, request):
if request.method == "POST": # action
print("POST:", request.POST)
action = request.POST.get("action")
selected_pk = request.POST.getlist("selected_pk") # 拿到列表
# 反射
# self这里是配置类BookConfig,要在类中找到对应的函数
action_func = getattr(self, action) # patch_init
# 拿到选中状态的pk值对象
queryset = self.model.objects.filter(pk__in=selected_pk) # <QuerySet [<Book: go>]>
action_func(request, queryset) # 获取search的Q对象
search_condition = self.get_search_condition(request)
# 筛选当前表获取的数据
data_list = self.model.objects.all().filter(search_condition) # 获取showlist展示页面
show_list = ShowList(self, data_list, request) header_list = show_list.get_header()
new_data_list = show_list.get_body() # 构建一个查看url
add_url = self.get_add_url()
print("add_url", add_url)
return render(request, "list_view.html", locals())

  在这里POST请求处理不需要返回值,批量初始化后,数据库已经更改,代码顺着下来紧接着就是查询拿到新的页面。

(3)配置校验

class BookConfig(ModelStark):
list_display = ["title", "price", "publishDate"]
modelform_class = BookModelForm
search_fields = ['title', "price"] def patch_init(self, request, queryset):
print(queryset)
queryset.update(price=123) patch_init.short_description = "批量初始化" actions = [patch_init] site.register(Book, BookConfig)

app01/stark.py

  显示效果:

  

4、添加admin批量操作自带的delete功能

class ShowList(object):
def __init__(self, config, data_list, request):
self.config = config # 接收传递过来的配置类对象 ModelStark的实例对象
self.data_list = data_list # 接收传递过来的当前表的所有对象
self.request = request # <WSGIRequest: GET '/stark/app01/book/?page=2'>
# 分页
data_count = self.data_list.count()
current_page = int(self.request.GET.get("page", 1)) # 默认是第一页
base_path = self.request.path # /stark/app01/book/ self.pagination = Pagination(current_page, data_count, base_path, self.request.GET, per_page_num=3, pager_count=11,)
self.page_data = self.data_list[self.pagination.start:self.pagination.end] # actions
# self.actions = self.config.actions # 拿到配置好的函数对象列表 [patch_init,]
self.actions = self.config.new_actions() # 拿到方法运行的返回结果 def get_action_list(self):
"""获取自定义批量操作"""
temp = []
for action in self.actions:
temp.append({
"name": action.__name__, # 函数.__name__:拿到函数名
"desc": action.short_description
}) # [{"name": "patch_init", "desc": "批量处理"}]
return temp class ModelStark(object):
"""默认类,定制配置类"""
list_display = ["__str__",]
list_display_links = []
modelform_class = []
search_fields = []
actions = [] # 调用self.actions拿到的是函数 def __init__(self, model, site):
self.model = model
self.site = site def patch_delete(self, request, queryset):
"""默认批量删除操作"""
queryset.delete() patch_delete.short_description = "批量删除" def new_actions(self):
"""返回所有批量操作"""
temp = []
# 默认添加批量删除
temp.append(ModelStark.patch_delete)
# 添加自定义action
temp.extend(self.actions)
return temp

  在new_actions实例方法中,首先可以通过ModelStark.patch_delete固定拿到默认需要添加的批量删除方法。其次ModelStark类中默认actions=[],因此在自定义配置类有配置actions时,self.actions拿到默认配置类配置的列表,如果没有配置拿到空列表。然后通过extend函数扩展列表返回所有批量操作函数。

  ShowList实例化时,self.actions属性通过self.config.new_actions()拿到new_actions返回结果。然后在模板上就可以通过show_list.config.actions渲染所有的actions操作了。

  显示效果:

1)自定义配置类没有配置actions:

  

2)自定义配置类配置了actions:

stark——分页、search、actions的更多相关文章

  1. day 68crm(5) 分页器的进一步优化,以及在stark上使用分页器,,以及,整理代码,以及stark组件search查询

    前情提要: 本节内容 自定制分页器 保存及查询记录 代码整理, stark组件search 查询    一:自定制分页器 page 1:创建类 Pagination  # 自定制分页器 _ _init ...

  2. stark - 分页、search、actions

    一.分页 效果图 知识点 1.分页 {{ showlist.pagination.page_html|safe }} 2.page.py class Pagination(object): def _ ...

  3. 模拟Django的admin自定义stark组件

    1.新建Django项目--新建app:app01和stark--在settings中配置app和数据库--在models.py中新建模型表--完成数据库迁移 2.在stark下的apps.py中: ...

  4. QIDO-RS - Search

    6.7.1 QIDO-RS - Search 6.7.1.1 Request The specific resources to be used for the search actions shal ...

  5. bootstrap table 服务器端分页--ashx+ajax

    1.准备静态页面 1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta http-equiv="Content-T ...

  6. Django之stark组件1

    stark组件 stark组件是根据Django admin为原型写的一个组件,能够让我们告别增删改查.stark组件是可插拔试的组件, 移植性强,而且只用配置文件就能够得到想要的数据 一.stark ...

  7. 10.21CRM项目(01)

    2018-10-21 13:35:19 crm第一天!放上初始源码! 后面等做完最后一天的手放上所有源码! 越努力越幸运!永远不要高估自己! 注意 多层for循环的时候,切记,不要名字重复!啦!!!! ...

  8. 10.19stark组件开发(三)

    2018-10-19 15:42:15 2018-10-19 18:21:33 我觉得现在主要是学一种解决问题的思路,也就是逻辑或者说是算法!!!! 要有对代码的感触!要用面向对象对类进行封装!!Dj ...

  9. Django - 学习目录

    Django 基础 web应用/http协议/web框架 Django简介 Django - 路由层(URLconf) Django - 视图层 Django - 模板层 Django - 模型层 - ...

随机推荐

  1. Python之路迭代器协议、for循环机制、三元运算、列表解析式、生成器

    Python之路迭代器协议.for循环机制.三元运算.列表解析式.生成器 一.迭代器协议 a迭代的含义 迭代器即迭代的工具,那什么是迭代呢? #迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的 ...

  2. StyleSheet

    StyleSheet.create()方法 //定义组件 var App = React.createClass({ render:function () { return( <View sty ...

  3. docker 使用save和load命令来转移image

    ——假设一个image叫ubuntu—— 在本机执行sudo docker save -o ubuntu.tar ubuntu 由此得到了 ubuntu.tar 文件,将其拷贝到远程机器,执行 sud ...

  4. SQL语句练习45题(从第11题开始)

    CREATE TABLE student (sno VARCHAR(3) NOT NULL, sname VARCHAR(4) NOT NULL, ssex VARCHAR(2) NOT NULL, ...

  5. telnet出现Connection closed by foreign host

    2018-10-26 执行命令: telnet smtp.exmail.qq.com 出现信息: [root@pengman Desktop]# telnet Tring Connected to 1 ...

  6. 剑指offer——面试题15.2:判断两个整数m和n的二进制中相差多少位

    #include"iostream" using namespace std; int CountDifferentBit(int m,int n) { ,diff=m^n; wh ...

  7. EntityFramework 建立一对一关系

    前言:本来要使用实体拆分实现一对一,但发现查询时无法单独查询,影响效率,故改用手动建立一对一关系 例: 实体类: public class TestDbContext : DbContext { pu ...

  8. PIE SDK彩色空间变换

    1. 算法功能简介 使用彩色空间变换工具可以将三波段红.绿.蓝图像变换到一个特定的彩色空间,并且能从所选彩色空间变换回 RGB.两次变换之间,通过对比度拉伸,可以生成一个色彩增强的彩色合成图像.此外, ...

  9. python学习9-生成器(转载)

    什么是生成器? 生成器的实质就是迭代器,我们能够从生成器中一个一的拿值 python中获取生成器的方式有三种: 1.通过生成器函数 2.通过生成器表达式 3.通过数据转换也可以获取生成器(某些对象执行 ...

  10. C#DataTable与Model互转

    /// <summary> /// 实体转换辅助类 /// </summary> public class ModelConvertHelper<T> where ...