一、分页

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. JVM高级特性与实践(一):Java内存区域 与 内存溢出异常

    套用<围城>中的一句话,“墙外面的人想进去,墙里面的人想出来”,用此来形容Java与C++之间这堵内存动态分配和垃圾收集技术所围成的“围墙”就再合适不过了. 对于从事C.C++的开发人员而 ...

  2. c语言数据结构学习心得——线性表

    线性表:具有相同数据类型的n(n>0)个数据元素的有限序列. 主要有顺序存储和链式存储. 顺序存储: 特点:地址连续,随机/存取,顺序存储. 建立:首地址/存储空间大小(数组),表长. 方式:静 ...

  3. [llvm] LLVM 核心类简明示例 : llvm::Value && llvm::Type && llvm::Constant

    LLVM 核心类简明示例 : llvm::Value && llvm::Type && llvm::Constant llvm核心类位于 include/llvm/IR ...

  4. PHP中使用CURL之php curl详细解析和常见大坑

    这篇文章主要介绍了PHP中使用CURL之php curl详细解析和常见大坑 ,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 七夕啦,作为开发,妹子没得撩就“撩”下服务器吧,妹子有得撩的同学 ...

  5. flex 实例Demo

    Flex 页面布局 很方便 快捷 <!DOCTYPE html> <html lang="en"> <head> <meta charse ...

  6. 针对animationend和transitionend多次执行的问题解决方案

    对于animationend事件来说的话,如果我们在外层添加这个事件监听,如果监听元素里面还有动画,则里面元素动画结束也会执行这个animationend事件.所以我们可以这样做: if(e.targ ...

  7. css3 超出文本...显示

    width: 250px 或者 100%; max-width: 285px; overflow: hidden; display: inline-block; white-space: nowrap ...

  8. Windows10 下安装配置IIS + MySQL5.7.19 + nginx1.12.1 + php7.1.7

    环境: VMWare Workstation Player12 Windows10 Pro x64 一.安装系统 vmware 会采用 fast install 方式很快装完,无需配置什么. 二.配置 ...

  9. KD树的极简单笔记(待后续更新)

    今天(18.5.4)室友A突然问我算法怎么入门,兴奋之下给他安利了邓公的<数据结构>,然而他接着又问我能不能两周内快速入门,毕竟打算搞Machine Learning,然后掏出手机看了下他 ...

  10. java 上传文件到 ftp 服务器

    1.  java 上传文件到 ftp 服务器 package com.taotao.common.utils; import java.io.File; import java.io.FileInpu ...