strak组件(10):批量操作
效果图:
批量删除只是一个例子,可以根据需求定制自己想要的批量操作。
新增函数
- def get_action_list(self) 钩子方法,获取要处理的批量操作的函数
- def action_multi_delete(self, request, *args, **kwargs) 批量删除
一、strak组件
- import functools
- from types import FunctionType
- from django import forms
- from django.db.models import Q
- from django.http import QueryDict
- from django.urls import re_path
- from django.utils.safestring import mark_safe
- from django.shortcuts import HttpResponse, render, reverse, redirect
- from stark.utils.pagination import Pagination
- class StarkModelForm(forms.ModelForm):
- def __init__(self, *args, **kwargs):
- super(StarkModelForm, self).__init__(*args, **kwargs)
- # 统一给ModelForm生成字段添加样式
- for name, field in self.fields.items():
- field.widget.attrs['class'] = 'form-control'
- def get_choice_text(title, field):
- """
- 对于Stark组件中定义列时,choice如果想要显示中文信息,调用此方法即可。
- :param title: 希望页面显示的表头
- :param field: 字段名称
- :return:
- """
- def inner(self, obj=None, is_header=None):
- if is_header:
- return title
- method = f"get_{field}_display"
- return getattr(obj, method)()
- # GENDER_CHOICES = ((MALE, '男'),(FEMALE, '女'),)
- # 对于choice字段,如果想获取获取第二个值,可以通过:对象.get_字段名_display()
- return inner
- class StarkHandler(object):
- list_display = []
- order_list = []
- search_list = []
- per_page_data = 10
- has_add_btn = True
- model_form_class = None
- list_template = None
- add_template = None
- edit_template = None
- delete_template = None
- action_list = []
- def __init__(self, site, model_class, prev):
- self.site = site
- self.model_class = model_class
- self.prev = prev
- self.request = None
- def display_checkbox(self, obj=None, is_header=None, *args, **kwargs):
- """
- 复选框
- :param obj:
- :param is_header:
- :param args:
- :param kwargs:
- :return:
- """
- if is_header:
- return '选择'
- return mark_safe(f'<input type="checkbox" name="pk" value="{obj.pk}" />')
- def display_edit(self, obj=None, is_header=None, *args, **kwargs):
- """
- 自定义页面显示的列(表头和内容)
- :param obj:
- :param is_header:
- :return:
- """
- if is_header:
- return '编辑'
- name = f'{self.site.namespace}:{self.get_edit_url_name}'
- return mark_safe(f'<a href="{reverse(name, args=(obj.pk,))}">编辑</a>')
- def display_delete(self, obj=None, is_header=None, *args, **kwargs):
- if is_header:
- return '删除'
- name = f'{self.site.namespace}:{self.get_delete_url_name}'
- return mark_safe(f'<a href="{reverse(name, args=(obj.pk,))}">删除</a>')
- def get_list_display(self, request, *args, **kwargs):
- """
- 获取页面上应该显示的列,预留的自定义扩展,例如:以后根据用户的不同显示不同的列
- :return:
- """
- value = []
- value.extend(self.list_display)
- return value
- def get_search_list(self):
- return self.search_list
- def get_add_btn(self, *args, **kwargs):
- if self.has_add_btn:
- return f'<a class="btn btn-primary" href="{self.reverse_add_url(*args, **kwargs)}">添加</a>'
- def get_model_form_class(self, request, *args, **kwargs):
- if self.model_form_class:
- return self.model_form_class
- class DynamicModelForm(StarkModelForm):
- class Meta:
- model = self.model_class
- fields = '__all__'
- return DynamicModelForm
- def get_order_list(self):
- return self.order_list or ['-id', ]
- def get_action_list(self):
- return self.action_list
- def action_multi_delete(self, request, *args, **kwargs):
- """
- 批量删除(如果想要定制执行成功后的返回值,那么就为action函数设置返回值即可)
- :param request:
- :param args:
- :param kwargs:
- :return:
- """
- pk_list = request.POST.getlist('pk')
- self.model_class.objects.filter(id__in=pk_list).delete()
- action_multi_delete.text = '批量删除'
- def list_view(self, request, *args, **kwargs):
- """
- 列表页面
- :param request:
- :return:
- """
- # 1. 处理Action
- action_list = self.get_action_list()
- action_dict = {func.__name__: func.text for func in action_list}
- if request.method == 'POST':
- action_func_name = request.POST.get('action')
- if action_func_name and action_func_name in action_dict:
- action_response = getattr(self, action_func_name)(request, *args, **kwargs)
- if action_response:
- return action_response
- # 2. 处理搜索
- # 搜索列表写ORM语句,如:['name__contains','email__contains','id__gt','gender']
- search_list = self.get_search_list()
- search_value = request.GET.get('q', '')
- conn = Q()
- conn.connector = 'OR' # 通过or链接
- if search_value:
- for item in search_list:
- conn.children.append((item, search_value)) # conn.children.append('name__contains','张三')
- # 3. 获取排序
- order_list = self.get_order_list()
- queryset = self.model_class.objects.filter(conn).order_by(*order_list)
- # 4. 分页处理
- all_count = queryset.count()
- query_params = request.GET.copy() # 深copy
- query_params._mutable = True # query_params默认不可修改
- pager = Pagination(
- current_page=request.GET.get('page'),
- all_count=all_count,
- base_url=request.path_info,
- query_params=query_params,
- per_page_data=self.per_page_data,
- )
- data_list = queryset[pager.start:pager.end]
- # 5. 处理表格
- list_display = self.get_list_display(request, *args, **kwargs) # 会优先调用UserInfoHandler里的get_list_display()方法。
- # 5.1 处理表格的表头
- header_list = []
- if list_display:
- for field_or_func in list_display:
- if isinstance(field_or_func, FunctionType):
- verbose_name = field_or_func(self, obj=None, is_header=True)
- else:
- verbose_name = self.model_class._meta.get_field(field_or_func).verbose_name
- header_list.append(verbose_name)
- else:
- header_list.append(self.model_class._meta.model_name) # 如果用户没有填写list_display,就显示表名
- # 5.2 处理表的内容
- body_list = []
- for obj in data_list:
- tr_list = []
- if list_display:
- for field_or_func in list_display:
- if isinstance(field_or_func, FunctionType):
- tr_list.append(field_or_func(self, obj, is_header=False, *args, **kwargs))
- else:
- tr_list.append(getattr(obj, field_or_func))
- else:
- tr_list.append(obj) # 如果用户没有填写list_display,就显示表对象,所以表类要定义__str__方法
- body_list.append(tr_list)
- # 6 添加按钮
- add_btn = self.get_add_btn(*args, **kwargs)
- context = {
- 'data_list': data_list,
- 'header_list': header_list,
- 'body_list': body_list,
- 'pager': pager,
- 'add_btn': add_btn,
- 'search_list': search_list,
- 'search_value': search_value,
- 'action_dict': action_dict,
- }
- return render(request, self.list_template or 'stark/data_list.html', context)
- def save(self, form, is_update=False, *args, **kwargs):
- """
- 在使用ModelForm保存数据之前预留的钩子方法
- :param form:
- :param is_update:
- :return:
- """
- form.save()
- def add_view(self, request, *args, **kwargs):
- """
- 添加页面
- :param request:
- :return:
- """
- model_form_class = self.get_model_form_class(request, *args, **kwargs)
- if request.method == 'GET':
- form = model_form_class()
- return render(request, 'stark/change.html', {'form': form})
- form = model_form_class(data=request.POST)
- if form.is_valid():
- self.save(form, False, *args, **kwargs)
- # 在数据库保存成功后,跳转回列表页面(携带原来的参数)。
- return redirect(self.reverse_list_url(*args, **kwargs))
- return render(request, self.add_template or 'stark/change.html', {'form': form})
- def edit_view(self, request, pk, *args, **kwargs):
- """
- 编辑页面
- :param request:
- :return:
- """
- current_edit_object = self.model_class.objects.filter(pk=pk).first()
- if not current_edit_object:
- return HttpResponse('要修改的数据不存在,请重新选择')
- model_form_class = self.get_model_form_class(request, *args, **kwargs)
- if request.method == 'GET':
- form = model_form_class(instance=current_edit_object)
- return render(request, 'stark/change.html', {'form': form})
- form = self.model_form_class(data=request.POST, instance=current_edit_object)
- if form.is_valid:
- self.save(form, True, *args, **kwargs)
- # 在数据库保存成功后,跳转回列表页面(携带原来的参数)
- return redirect(self.reverse_list_url(*args, **kwargs))
- return render(request, 'stark/change.html', {'form': form})
- def delete_view(self, request, pk, *args, **kwargs):
- """
- 删除页面
- :param request:
- :param pk:
- :return:
- """
- original_list_url = self.reverse_list_url(*args, **kwargs)
- if request.method == 'GET':
- return render(request, 'stark/delete.html', {'cancel': original_list_url})
- self.model_class.objects.filter(pk=pk).delete()
- return redirect(original_list_url)
- def get_url_name(self, params):
- app_label, model_name = self.model_class._meta.app_label, self.model_class._meta.model_name
- if self.prev:
- return f'{app_label}_{model_name}_{self.prev}_{params}'
- return f'{app_label}_{model_name}__{params}'
- @property
- def get_list_url_name(self):
- """
- 获取列表页面URL的name
- :return:
- """
- return self.get_url_name('list')
- @property
- def get_add_url_name(self):
- """
- 获取添加页面URL的name
- :return:
- """
- return self.get_url_name('add')
- @property
- def get_edit_url_name(self):
- """
- 获取编辑页面URL的name
- :return:
- """
- return self.get_url_name('edit')
- @property
- def get_delete_url_name(self):
- """
- 获取删除页面URL的name
- :return:
- """
- return self.get_url_name('delete')
- def reverse_common_url(self, name, *args, **kwargs):
- """
- 生成带有原搜索条件的URL
- :param name: url
- :param args:
- :param kwargs:
- :return:
- """
- name = f'{self.site.namespace}:{name}'
- base_url = reverse(name, args=args, kwargs=kwargs)
- if not self.request.GET:
- reverse_url = base_url
- else:
- params = self.request.GET.urlencode()
- new_query_dict = QueryDict(mutable=True)
- new_query_dict['_filter'] = params
- reverse_url = f'{base_url}?{new_query_dict.urlencode()}'
- return reverse_url
- def reverse_add_url(self, *args, **kwargs):
- """
- 带有原搜索条件的增加URL
- :param args:
- :param kwargs:
- :return:
- """
- return self.reverse_common_url(self.get_add_url_name, *args, **kwargs)
- def reverse_edit_url(self, *args, **kwargs):
- """
- 带有原搜索条件的编辑URL
- :param args:
- :param kwargs:
- :return:
- """
- return self.reverse_common_url(self.get_edit_url_name, *args, **kwargs)
- def reverse_delete_url(self, *args, **kwargs):
- """
- 带有原搜索条件的删除URL
- :param args:
- :param kwargs:
- :return:
- """
- return self.reverse_common_url(self.get_delete_url_name, *args, **kwargs)
- def reverse_list_url(self, *args, **kwargs):
- name = f'{self.site.namespace}:{self.get_list_url_name}'
- base_url = reverse(name, args=args, kwargs=kwargs)
- params = self.request.GET.get('_filter')
- if not params:
- return base_url
- return f'{base_url}?{params}'
- def wrapper(self, func):
- """
- 当每一个request请求进来的时候,把request赋值给类的数据属性self.request
- :param func: request请求对应的视图函数
- :return:
- """
- @functools.wraps(func) # 保留原函数的原信息,写装饰器建议写上这个。
- def inner(request, *args, **kwargs):
- self.request = request
- return func(request, *args, **kwargs)
- return inner
- def get_urls(self):
- patterns = [
- re_path(r'^list/$', self.wrapper(self.list_view), name=self.get_list_url_name),
- re_path(r'^add/$', self.wrapper(self.add_view), name=self.get_add_url_name),
- re_path(r'^edit/(\d+)/$', self.wrapper(self.edit_view), name=self.get_edit_url_name),
- re_path(r'^delete/(\d+)/$', self.wrapper(self.delete_view), name=self.get_delete_url_name),
- ]
- patterns.extend(self.extra_urls())
- return patterns
- def extra_urls(self):
- return []
- class StarkSite(object):
- def __init__(self):
- self._registry = []
- self.app_name = 'stark'
- self.namespace = 'stark'
- def register(self, model_class, handler_class=None, prev=None):
- """
- :param model_class: 是models中的数据库表对应的类。
- :param handler_class: 处理请求的视图函数所在的类
- :param prev: 生成URL的前缀
- :return:
- """
- if not handler_class:
- handler_class = StarkHandler
- self._registry.append(
- {'model_class': model_class, 'handler': handler_class(self, model_class, prev), 'prev': prev})
- def get_urls(self):
- patterns = []
- for item in self._registry:
- model_class = item['model_class']
- handler = item['handler']
- prev = item['prev']
- app_name, model_name = model_class._meta.app_label, model_class._meta.model_name
- if prev:
- patterns.append(
- re_path(rf'^{app_name}/{model_name}/{prev}/', (handler.get_urls(), None, None)))
- else:
- patterns.append(
- re_path(rf'^{app_name}/{model_name}/', (handler.get_urls(), None, None)))
- return patterns
- @property
- def urls(self):
- return self.get_urls(), self.app_name, self.namespace
- site = StarkSite()
二、业务代码
- from stark.service.core_func import site, StarkHandler, StarkModelForm, get_choice_text
- from web import models
- class UserInfoModelForm(StarkModelForm):
- class Meta:
- model = models.UserInfo
- fields = ['name', 'gender', 'classes', 'age', 'email']
- class DepartmentHandler(StarkHandler):
- list_display = ['title']
- class UserInfoHandler(StarkHandler):
- per_page_data = 5
- order_list = ['gender']
- model_form_class = UserInfoModelForm
- search_list = ['name__contains', 'email__contains', ]
- action_list = [StarkHandler.action_multi_delete, ]
- list_display = [
- StarkHandler.display_checkbox,
- 'name',
- get_choice_text('性别', 'gender'),
- get_choice_text('班级', 'classes'),
- 'age', 'email', 'department',
- StarkHandler.display_edit,
- StarkHandler.display_delete,
- ]
- def save(self, form, is_update=False, *args, **kwargs):
- form.instance.department_id = 1
- form.save()
- site.register(models.Department, DepartmentHandler) # 给部门的url增加了前缀:/stark/web/department/private/
- site.register(models.UserInfo, UserInfoHandler)
三、模板渲染
- {% extends 'layout.html' %}
- {% block css %}
- <link rel="stylesheet" href="">
- {% endblock css %}
- {% block content %}
- <div class="custom-container">
- <!-- 搜索 -->
- {% if search_list %}
- <div class="up-down-space right">
- <form method="get" class="form-inline">
- <div class="form-group">
- <input class="form-control" type="text" name="q" value="{{ search_value }}"
- placeholder="关键字搜搜">
- <button class="btn btn-primary" type="submit">
- <i class="fa fa-search" aria-hidden="true"></i>
- </button>
- </div>
- </form>
- </div>
- {% endif %}
- <!-- 搜索结束 -->
- <!-- 批量操作 -->
- <form method="post" class="form-inline">
- {% csrf_token %}
- {% if action_dict %}
- <div class="left up-down-space">
- <div class="form-group">
- <select class="form-control" name="action">
- <option value="">请选择操作</option>
- {% for func_name,func_text in action_dict.items %}
- <option value="{{ func_name }}">{{ func_text }}</option>
- {% endfor %}
- </select>
- <input class="btn btn-primary" type="submit" value="执行"/>
- </div>
- </div>
- {% endif %}
- <!-- 批量操作结束 -->
- <!-- 添加按钮开始 -->
- {% if add_btn %}
- <div class="up-down-space left add_btn">
- {{ add_btn|safe }}
- </div>
- {% endif %}
- <!-- 添加按钮结束 -->
- <table class="table table-bordered">
- <thead>
- <tr>
- {% for item in header_list %}
- <th>{{ item }}</th>
- {% endfor %}
- </tr>
- </thead>
- <tbody>
- {% for row in body_list %}
- <tr>
- {% for ele in row %}
- <td>{{ ele }}</td>
- {% endfor %}
- </tr>
- {% endfor %}
- </tbody>
- </table>
- </form>
- <nav>
- <ul class="pagination">
- {{ pager.page_html|safe }}
- </ul>
- </nav>
- </div>
- {% endblock content %}
strak组件(10):批量操作的更多相关文章
- strak组件(9):关键字搜索
效果图: 在列表视图函数增加搜索功能. 新增函数 def get_search_list(self) 钩子方法,获取搜索条件 一.strak组件 strak/service/core_func.py ...
- Bootstrap入门(十六)组件10:well和具有响应式特性的嵌入内容
Bootstrap入门(十六)组件10:well和具有响应式特性的嵌入内容 well组件可以为内容增添一种切入效果. 具有响应式特性的嵌入内容可以根据被嵌入内容的外部容器的宽度,自动创建一个固定的比例 ...
- strak组件(6):列表定制列应用和引入静态文件
效果图: 新增函数 def get_choice_text(title, field) 闭包函数,显示choice字段 def inner(self, obj=None, is_header=None ...
- amazeui学习笔记--css(常用组件10)--导航条Topbar
amazeui学习笔记--css(常用组件10)--导航条Topbar 一.总结 1. 导航条:就是页面最顶端的导航条:在容器上添加 .am-topbar class,然后按照示例组织所需内容.< ...
- strak组件(8):基本增删改查实现及应用和排序
效果图: 新增函数: def reverse_common_url(self, name, *args, **kwargs) 反向生成url,需要传增删改的url作为参数,携带原参数 def reve ...
- stark组件之批量操作【模仿Django的admin】
一.先看下django的admin是如何实现批量操作 首先在配置类中定义一个函数 然后我们为这个函数对象设置一个属性,这个属性主要用来显示在select标签中显示的文本内容 最后把函数对象放到一个ac ...
- React入门---可复用组件-10
主要对props更多重要的特性进行学习; 还是用之前代码, index.js代码为: var React = require('react'); var ReactDOM = require('rea ...
- strak组件(5):为列表定制预留钩子方法
效果图: 新增函数 def get_list_display(self): 获取页面上应该显示的列,预留的自定义扩展,例如:以后根据用户的不同显示不同的 一.stark组件 stark/servic ...
- strak组件(3):URL别名的优化
将生成URL别名的功能进行解耦.效果和上一节的一样. 效果图: 新增函数 get_url_name(self, param) # 生成url别名,需要一个参数(list/add/edit/delete ...
随机推荐
- 粗看ES6之解构赋值
标签: javascript es6 什么是解构赋值? 示例如下: <!DOCTYPE html> <html> <head> <meta charset=& ...
- ajax提交 返回值为undefined
easyui form 表单提交成功,但是返回值为undefined,原因是返回值不是json格式,是字符串的格式,那么解决办法就是把其转化成json格式 示例: $(function () { / ...
- (二)JavaScript之[函数]与[作用域]
3].函数 /** * 事件驱动函数. * 函数执行可重复使用的代码 * * 1.带参的函数 * 2.带返回值的函数 * 3.局部变量 * * 4.全局变量 * 在函数外的:不用var声明,未声明直接 ...
- StackTrack for debug
System.Diagnostics.Debug.WriteLine("Serial port. {0},{1}", this.GetType().FullName, new Sy ...
- CloudWAN
类型: 定制服务 软件包: collaboration Enterprise integration integrated industry internet IT service/informati ...
- [topcoder]SRM 633 DIV 2
第一题,http://community.topcoder.com/stat?c=problem_statement&pm=13462&rd=16076 模拟就可以了. #includ ...
- javaWeb上移下移(SpringMVC+Mabits+MySql)
文章已移至:https://blog.csdn.net/baidu_35468322/article/details/79643356 移动之前: 移动之后: 1.控制层 /** * 修改排序 * * ...
- Java I/O 工作机制(二) —— Java 的 I/O 的交互方式分析
简介: BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善. ...
- C语言头文件怎么写?(转载)
---恢复内容开始--- c语言头文件怎么写?我一直有这样的疑问,但是也一直没去问问到底咋回事:所以今天一定要把它弄明白! 其实学会写头文件之后可以为我们省去不少事情,可以避免书写大量的重复代码,还在 ...
- openwrt定制管理
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/qianguozheng/article/details/24673097 近期这个比較火,可是改了东 ...