效果图:

新增函数:

def reverse_common_url(self, name, *args, **kwargs) 反向生成url,需要传增删改的url作为参数,携带原参数

def reverse_add_url(self, *args, **kwargs)  反向生成增加url,通过向reverse_common_url传参数生成,携带原参数

def reverse_edit_url(self, *args, **kwargs)  反向生成编辑url,通过向reverse_common_url传参数生成,携带原参数

def reverse_delete_url(self, *args, **kwargs)  反向生成删除url,通过向reverse_common_url传参数生成,携带原参数

def reverse_list_url(self)  反省生成列表页面url,携带原参数

def save(self, form, is_update=False, *args, **kwargs)  在使用ModelForm保存数据之前预留的钩子方法

def get_add_btn(self, *args, **kwargs)  显示增加按钮
 
def get_order_list(self) 获取排序,默认倒序

一、stark组件

stark/service/core_func.py

import functools
from types import FunctionType from django import forms
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 = "get_%s_display" % field
return getattr(obj, method)()
# GENDER_CHOICES = ((MALE, '男'),(FEMALE, '女'),)
# 对于choice字段,如果想获取获取第二个值,可以通过:对象.get_字段名_display() return inner class StarkHandler(object):
list_display = []
order_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 def __init__(self, site, model_class, prev):
self.site = site
self.model_class = model_class
self.prev = prev
self.request = None def display_edit(self, obj=None, is_header=None):
"""
自定义页面显示的列(表头和内容)
:param obj:
:param is_header:
:return:
"""
if is_header:
return '编辑'
name = '%s:%s' % (self.site.namespace, self.get_edit_url_name,)
return mark_safe('<a href="%s">编辑</a>' % reverse(name, args=(obj.pk,))) def display_delete(self, obj=None, is_header=None):
if is_header:
return '删除'
name = '%s:%s' % (self.site.namespace, self.get_delete_url_name,)
return mark_safe('<a href="%s">删除</a>' % reverse(name, args=(obj.pk,))) def get_list_display(self):
"""
获取页面上应该显示的列,预留的自定义扩展,例如:以后根据用户的不同显示不同的列
:return:
"""
value = []
value.extend(self.list_display)
return value def get_add_btn(self, *args, **kwargs):
if self.has_add_btn:
return '<a class="btn btn-primary" href="%s">添加</a>' % self.reverse_add_url(*args, **kwargs) def get_model_form_class(self):
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 list_view(self, request, *args, **kwargs):
"""
列表页面
:param request:
:return:
""" # 1.获取排序
order_list = self.get_order_list()
queryset = self.model_class.objects.all().order_by(*order_list) # 2.分页处理
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] # 3 处理表格
list_display = self.get_list_display() # 会优先调用UserInfoHandler里的get_list_display()方法。
# 3.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,就显示表名 # 3.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) # 4 添加按钮
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,
} return render(request, self.list_template or 'stark/data_list.html', context) def save(self, form, is_update, *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()
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()
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 '%s_%s_%s_%s' % (app_label, model_name, self.prev, params)
return '%s_%s_%s' % (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 = '%s:%s' % (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 = '%s?%s' % (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 = '%s:%s' % (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 '%s?%s' % (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(r'^%s/%s/%s/' % (app_name, model_name, prev,), (handler.get_urls(), None, None)))
else:
patterns.append(re_path(r'^%s/%s/' % (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
list_display = [
'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)

三、模板渲染

stark/templates/stark/change.html

{% extends 'layout.html' %}
{% block css %} <style>
ul {
list-style-type: none;
padding: 0;
} ul li {
float: left;
padding: 10px;
padding-left: 0;
width: 80px;
} ul li i {
font-size: 18px;
margin-left: 5px;
color: #6d6565;
} </style>
{% endblock %} {% block content %}
<div class="custom-container"> <form class="form-horizontal" method="post" novalidate>
{% csrf_token %} {% for field in form %}
<div class="form-group">
<label class="col-sm-2 control-label">{{ field.label }}</label>
<div class="col-sm-8">
{{ field }}
<span style="color: red;">{{ field.errors.0 }}</span>
</div>
</div>
{% endfor %}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-8">
<input type="submit" value="保 存" class="btn btn-primary">
</div>
</div> </form> </div> {% endblock %}

stark/templates/stark/delete.html

{% extends 'layout.html' %}

{% block content %}
<div class="custom-container">
<div class="alert alert-danger" role="alert">
<form method="post">
{% csrf_token %}
<p style="font-size: 13px;"><i class="fa fa-warning" aria-hidden="true"></i> 删除后将不可恢复,请确定是否删除?</p>
<div style="margin-top: 20px;">
<a href="{{ cancel }}" class="btn btn-default btn-sm">取消</a>
<input type="submit" class="btn btn-danger btn-sm" value="确 认">
</div>
</form>
</div>
</div>
{% endblock %}

strak/templates/data_list.html

{% extends 'layout.html' %}

{% block content %}
<div class="custom-container">
{% if add_btn %}
<div style="margin:10px 0">
{{ 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> <nav>
<ul class="pagination">
{{ pager.page_html|safe }}
</ul>
</nav>
</div>
{% endblock content %}

strak组件(8):基本增删改查实现及应用和排序的更多相关文章

  1. EF增删改查+使用Expression进行动态排序分页

    注:以下部分来自<ASP.NET MVC 企业级实战>一书的摘抄和改写以及部分个人学习心得. EF简单增删改查 增加 public static int Add() { using (No ...

  2. JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)

    前言:关于Vue框架,好几个月之前就听说过,了解一项新技术之后,总是处于观望状态,一直在犹豫要不要系统学习下.正好最近有点空,就去官网了解了下,看上去还不错的一个组件,就抽空研究了下.最近园子里vue ...

  3. JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(一)

    前言:出于某种原因,需要学习下Knockout.js,这个组件很早前听说过,但一直没尝试使用,这两天学习了下,觉得它真心不错,双向绑定的机制简直太爽了.今天打算结合bootstrapTable和Kno ...

  4. JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(四):自定义T4模板快速生成页面

    前言:上篇介绍了下ko增删改查的封装,确实节省了大量的js代码.博主是一个喜欢偷懒的人,总觉得这些基础的增删改查效果能不能通过一个什么工具直接生成页面效果,啥代码都不用写了,那该多爽.于是研究了下T4 ...

  5. JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(三):两个Viewmodel搞定增删改查

    前言:之前博主分享过knockoutJS和BootstrapTable的一些基础用法,都是写基础应用,根本谈不上封装,仅仅是避免了html控件的取值和赋值,远远没有将MVVM的精妙展现出来.最近项目打 ...

  6. JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(二)

    前言:上篇 JS组件系列——BootstrapTable+KnockoutJS实现增删改查解决方案(一) 介绍了下knockout.js的一些基础用法,由于篇幅的关系,所以只能分成两篇,望见谅!昨天就 ...

  7. 【ActionScript】ActionScript3.0对舞台组件的增删改查

    以一个样例来说明ActionScript3.0对舞台组件的增删改查 例如以下图: 在Flash执行的时候,通过脚本.斜向下生成text0-text9十个文本节点. 提供两个功能. 1.在右上角,用户输 ...

  8. VUE2.0增删改查附编辑添加model(弹框)组件共用

    Vue实战篇(增删改查附编辑添加model(弹框)组件共用) 前言 最近一直在学习Vue,发现一份crud不错的源码 预览链接 https://taylorchen709.github.io/vue- ...

  9. popup的简单应用举例(具体在增删改查组件中用到)以及补充的知识点

    一.首先说一下自执行函数 1. 立即执行函数是什么?也就是匿名函数 立即执行函数就是 声明一个匿名函数 马上调用这个匿名函数 2.popup的举例 点击,弹出一个新的窗口.保存完事,页面不刷新数据就返 ...

随机推荐

  1. 根据tomcat日志查找想要的错误日志

    1.首先要记得程序报的错误信息 我的错误信息是[2015接收的参数中有空值],对应程序中的返回值是2015 以及出现错误信息的大致时间,我的大概是吃过午饭后,12:40-13:20之间 2.先去log ...

  2. tp3.2水印上传文件

    <html> <html lang="en"><head>    <meta charset="UTF-8">  ...

  3. jquery-validate插件

    jQuery Validation 插件 优点:1.表单验证非常简单方便,并且提供了许多配置项目2.国际化,可以自定义提示信息 命令行安装 //初始化bowerbower init //使用bower ...

  4. QtWebkits如何向QtWebEngine过渡

    QtWebkits如何向QtWebEngine过渡 1. 前言 很遗憾,QtWebkits在Qt5.6以上版本被淘汰了,对于这个接口良且和其他类例如QWebFrame完美结合的组件就这么没了,我只能表 ...

  5. *205. Isomorphic Strings (string & map idea)

    Given two strings s and t, determine if they are isomorphic. Two strings are isomorphic if the chara ...

  6. Aizu The Maximum Number of Customers

    http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_5_A The Maximum Number of Customers Ide ...

  7. LA 3902 网络

    题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_ ...

  8. Google搜索引擎使用小技巧

    相信大家都知道,利用Google等搜索引擎进行信息查证是翻译过程中十分重要的一环.事实上,掌握信息搜索的技巧和方法,不仅对翻译工作大有帮助, 在网络信息时代,学会充分利用搜索引擎,在很多情况下都可以达 ...

  9. 2018.7.27 Json与Java相互转换

    Json.jsp <%@ page language="java" contentType="text/html; charset=UTF-8" page ...

  10. IE 8 下小心使用console.log()

    我们很多情况下会使用console.log() 对代码调试.在chrome下和Firefox下都不会有太大问题,但是在最近我在IE8 下调试时使用了console.log(),就出现一些问题.在IE8 ...