stark 增删改
- 优雅装饰器
import functools def wrapper(func): @functools.wraps(func) # 保留原函数的信息 def inner(*args, **kwargs): return func(*args, **kwargs) return inner @wrapper def f1(): print('f1') @wrapper def f2(): print('f1') print(f1.__name__) print(f2.__name__) """ 之前 inner inner """ """ 之后 f1 f2 """
- 判断是函数,还是变量
判断arg是函数则打印1,arg是方法则打印2
from types import MethodType,FunctionType def check(arg): """ 判断arg是函数则打印1,arg是方法则打印2 :param arg: :return: """ if isinstance(arg,MethodType): print(2) elif isinstance(arg,FunctionType): print(1) else: print('不认识') def func(): pass class Foo(object): def display(self): pass check(func) check(Foo.display) check(Foo().display) """ 1 1 2 """
- 类传变量的一种方式
实例方法传参,要传实例对象本身
class RoleConfig(object): def f1(self, arg): print('f1', arg) def f2(self, arg): print('f2', arg) list_display = [f1, f2] obj = RoleConfig() for item in RoleConfig.list_display: item(obj, 2) # obj就是self,实例变量本身 # 传变量的一种方式
- 利用列表储存函数对象
一个进程两次调用类变量
class RoleConfig(object): def f1(self, arg): print('f1', arg) def f2(self, arg): print('f2', arg) def f3(self, arg): print('f3', arg) list_display = [f1, f2] def get_list_display(self): self.list_display.insert(0, RoleConfig.f3) return self.list_display obj1 = RoleConfig() for item in obj1.get_list_display(): item(obj1, 2) # 刚开始这时候列表里还没有,加进f3, obj2 = RoleConfig() for item in obj2.get_list_display(): print('obj2----') item(obj2, 6) # 这时候列表里有了f3,再插入一个f3反回。所以此处列表里有四个 # 利用类的变量列表,储存对象 # 一个进程对类操作了两次 """ f3 2 f1 2 f2 2 f3 6 f3 6 f1 6 f2 6 """
class RoleConfig(object): def f1(self, arg): print('f1', arg) def f2(self, arg): print('f2', arg) def f3(self, arg): print('f3', arg) list_display = [f1, f2] def get_list_display(self): v = [] v.extend(self.list_display) v.insert(0, RoleConfig.f3) return v obj1 = RoleConfig()#[f1,f2] for item in obj1.get_list_display():# [f3,f1,f2] item(obj1, 2) print('---------------') obj2 = RoleConfig()#[f1,f2] for item in obj2.get_list_display(): #[f3,f1,f2] item(obj2, 6) print('+++++') """ f3 2 --------------- f3 6 f1 6 f2 6 +++++ f1 2 --------------- f3 6 f1 6 f2 6 +++++ f2 2 --------------- f3 6 f1 6 f2 6 +++++ """
- 利用yield取数据
不要一次性取出来,占内存
以前的: def func(request): result = [] data_list = models.Users.objects.all() for row in data_list: temp = "%s%s" (row.name,row.pwd,) result.append(temp) return render(request,'xxx.html',{'result':result}) xxx.html {% for row in result %} {{row}} {% endfor%} 现在的: def get_result(data_list): for row in data_list: temp = "%s%s" (row.name,row.pwd,) yield temp def func(request): data_list = models.Users.objects.all() result = get_result(data_list) return render(request,'xxx.html',{'result':result}) xxx.html {# 生成器,不断去调用#} {% for row in result %} {{row}} {% endfor%}
复选框实现
- 复选框函数 mark_safe
def display_checkbox(self, row=None, header=False): # 选择框功能 默认None,表头 如果是表头,则显示相应字段 if header: return "选择" # 表头第一个字段,可以自定制 return mark_safe("<input type='checkbox' name='pk' value='%s' />" % row.pk) # 安全渲染**** 选中行数据pk
- 复选框函数实现与显示
调用复选框函数,拿到标签渲染
def changelist_view(self, request): # 所有URL的查看列表页面 # 获取表所有数据 queryset = self.model_class.objects.all().order_by(*self.get_order_by()) # 要显示的字段 list_display = self.list_display header_list = [] # 表头列表 if list_display: # 判断有没有显示字段 for name_or_func in list_display: if isinstance(name_or_func, FunctionType): # 判断是不是函数,是则执行 verbose_name = name_or_func(self, header=True) else: # 不是函数,则按规则去取字段的名称 verbose_name = self.model_class._meta.get_field(name_or_func).verbose_name header_list.append(verbose_name) else: # 没有显示字段列表,取表名作为表头 header_list.append(self.model_class._meta.model_name) body_list = [] # 表体列表 for row in queryset: # 从查找到的queryset对象里取 row_list = [] # 行列表 if not list_display: # 没有规定显示的字段 row_list.append(row) # 直接将一条queryset 放到行列表里面 body_list.append(row_list) # 再放到表体 continue for name_or_func in list_display: # 按照要显示的字段,取数据,遇到函数就执行显示复选框,并返回该行对象 if isinstance(name_or_func, FunctionType): # 判断是否是功能函数 val = name_or_func(self, row=row) # 执行函数反回功能内容 else: # 其他字段的数据正常取 val = getattr(row, name_or_func) # getattr 映射 每个要显示字段名 ,取queryset里面的字段值 row_list.append(val) # 添加到行 body_list.append(row_list) # 添加到表体 # 反回渲染页面 return render(request, 'stark/changelist.html', {'header_list': header_list, 'body_list': body_list})
- 前端页面
循环取值
<div> <table class="table table-bordered"> {# 基于bootstrap 创建table表 #} <thead> {# 表头 #} <tr> {% for item in header_list %} <th>{{ item }}</th> {% endfor %} </tr> </thead> <tbody> {# 表体 #} {% for row_list in body_list %} <tr> {% for col in row_list %} <td>{{ col }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </div>
- 自定义的配置类
from stark.service.stark import site, StarkConfig from app01 import models site.register(models.UserInfo) class DepartConfig(StarkConfig): # 自定义的配置类 list_display = [StarkConfig.display_checkbox,'id', 'name', 'user'] # 自定义的显示字段 site.register(models.Depart, DepartConfig)
编辑删除功能函数实现
利用函数封装名称标签,组装表每行时 Functiontype判断,取不同值放入row_list
def display_edit(self, row=None, header=False): if header: return "编辑" return mark_safe('<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a>' % self.reverse_edit_url(row)) def display_del(self, row=None, header=False): if header: return "删除" return mark_safe('<a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a>' % self.reverse_del_url(row)) def display_edit_del(self, row=None, header=False): if header: return "操作" tpl = """<a href="%s"><i class="fa fa-edit" aria-hidden="true"></i></a></a> | <a href="%s"><i class="fa fa-trash-o" aria-hidden="true"></i></a> """ %(self.reverse_edit_url(row),self.reverse_del_url(row),) return mark_safe(tpl)
前端循环取组装好的列表里面的值即可
{% block content %} <div> {% if add_btn %} <div style="margin: 5px 0;"> {{ add_btn }} </div> {% endif %} <table class="table table-bordered"> <thead> <tr> {% for item in header_list %} <th>{{ item }}</th> {% endfor %} </tr> </thead> <tbody> {% for row_list in body_list %} <tr> {% for col in row_list %} <td>{{ col }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </div> {% endblock %}
添加数据功能实现
modeform 实现表单更改验证
model_form_class = None def get_add_btn(self): return mark_safe('<a href="%s" class="btn btn-success">添加</a>' % self.reverse_add_url()) def get_model_form_class(self): """ 获取ModelForm类 # 用于编辑 和 添加数据的表单 :return: #根据是否有自定义配置,返回不同表单 """ if self.model_form_class: return self.model_form_class # 其他表的配置,如果有自定义的表单则返回自定义的 class AddModelForm(forms.ModelForm): # 添加功能的表单,所有数据都需要填写,所以默认所有字段都要 class Meta: model = self.model_class fields = "__all__" return AddModelForm
def changelist_view(self, request): """ 所有URL的查看列表页面 # 将添加按钮功能,添加到这页面视图 :param request: :return: """ queryset = self.model_class.objects.all().order_by(*self.get_order_by()) # ##### 添加按钮 ###### add_btn = self.get_add_btn() ...... def add_view(self, request): """ 所有添加页面,都在此函数处理 使用ModelForm实现 :param request: :return: """ AddModelForm = self.get_model_form_class() if request.method == "GET": form = AddModelForm() return render(request, 'stark/change.html', {'form':form}) form = AddModelForm(request.POST) # 校验数据 if form.is_valid(): form.save() # 保存 return redirect(self.reverse_list_url()) # 添加完反回主页面 return render(request, 'stark/change.html', {'form': form})
class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self, model_class, stark_config=None): """ 注册表类 :param model_class: 表类class :param stark_config: 自定义配置 :return: """ if not stark_config: stark_config = StarkConfig self._registry[model_class] = stark_config(model_class, self) # 实例对象传参 """ { models.UserInfo: StarkConfig(models.UserInfo), # 封装:model_class=UserInfo,site=site对象 models.Role: RoleConfig(models.Role) # 封装:model_class=Role,site=site对象 } """ def get_urls(self): # 获取url urlpatterns = [] #url 列表 # urlpatterns.append(url(r'^x3/', ([ # url(r'^add/', self.x1), # url(r'^change/', self.x1), # url(r'^del/', self.x1), # url(r'^edit/', self.x1), # ],None,None))) for k, v in self._registry.items(): # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封装:model_class=UserInfo,site=site对象 # k=modes.Role,v=RoleConfig(models.Role) # 封装:model_class=Role,site=site对象 app_label = k._meta.app_label model_name = k._meta.model_name urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None))) # 表类所在app/表类名的组装 一个表类绑定的操作url return urlpatterns @property def urls(self): return self.get_urls(), self.app_name, self.namespace # url列表 # 返回的元组 site = AdminSite()
def change_view(self, request, pk): """ 所有编辑页面 :param request: :param pk: 操作该条数据的pk,路由有设置 :return: """ obj = self.model_class.objects.filter(pk=pk).first() if not obj: return HttpResponse('数据不存在') ModelFormClass = self.get_model_form_class() if request.method == 'GET': form = ModelFormClass(instance=obj) # instance=obj 默认原先的编辑数据 return render(request,'stark/change.html',{'form':form}) form = ModelFormClass(data=request.POST,instance=obj) if form.is_valid(): form.save() return redirect(self.reverse_list_url()) return render(request, 'stark/change.html', {'form': form})
{% block content %} <div style="width: 680px;margin: 0 auto;"> <form class="change" method="post"> {% csrf_token %} {% for filed in form %} <div class="form-group"> <label>{{ filed.label }}</label> {{ filed }} {{ filed.errors.0 }} </div> {% endfor %} <button type="submit" class="btn btn-default">Submit</button> </form> </div> {% endblock %}
def delete_view(self, request, pk): """ 所有删除页面 :param request: :param pk: :return: """ if request.method == "GET": return render(request,'stark/delete.html',{'cancel_url':self.reverse_list_url()}) # 跳转到确认页面 # 取消反回的url self.model_class.objects.filter(pk=pk).delete() # 不是GET请求,说明确认删除 return redirect(self.reverse_list_url())
{% extends 'stark/layout.html' %} {% block css %} {% endblock %} {% block content %} <div > <form method="post"> {% csrf_token %} <p>是否确定要删除?</p> <a href="{{ cancel_url }}" class="btn btn-default">取消</a> <button type="submit" class="btn btn-danger">确 认</button> </form> </div> {% endblock %}
def get_urls(self): info = self.model_class._meta.app_label, self.model_class._meta.model_name urlpatterns = [ url(r'^list/$', self.wrapper(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', self.wrapper(self.add_view), name='%s_%s_add' % info), url(r'^(?P<pk>\d+)/change/', self.wrapper(self.change_view), name='%s_%s_change' % info), url(r'^(?P<pk>\d+)/del/', self.wrapper(self.delete_view), name='%s_%s_del' % info), ] extra = self.extra_url() if extra: urlpatterns.extend(extra) return urlpatterns def extra_url(self): pass
反向解析,前端提交变更的路由路径
def reverse_list_url(self): app_label = self.model_class._meta.app_label model_name = self.model_class._meta.model_name namespace = self.site.namespace name = '%s:%s_%s_changelist' % (namespace, app_label, model_name) list_url = reverse(name) return list_url def reverse_add_url(self): app_label = self.model_class._meta.app_label model_name = self.model_class._meta.model_name namespace = self.site.namespace name = '%s:%s_%s_add' % (namespace, app_label, model_name) add_url = reverse(name) return add_url def reverse_edit_url(self,row): app_label = self.model_class._meta.app_label model_name = self.model_class._meta.model_name namespace = self.site.namespace name = '%s:%s_%s_change' % (namespace, app_label, model_name) edit_url = reverse(name, kwargs={'pk': row.pk}) return edit_url def reverse_del_url(self,row): app_label = self.model_class._meta.app_label model_name = self.model_class._meta.model_name namespace = self.site.namespace name = '%s:%s_%s_del' % (namespace, app_label, model_name) del_url = reverse(name, kwargs={'pk': row.pk}) return del_url @property def urls(self): return self.get_urls()
应用配置app01/stark.py
class DepartModelForm(forms.ModelForm): class Meta: model = models.Depart fields = "__all__" def clean_name(self): return self.cleaned_data['name'] class DepartConfig(StarkConfig): #继承默认配置类 list_display = [StarkConfig.display_checkbox, 'id', 'name', 'tel', 'user', StarkConfig.display_edit_del] model_form_class = DepartModelForm def changelist_view(self, request): return HttpResponse('自定义列表页面') site.register(models.Depart, DepartConfig)
注册类入口
class AdminSiteclass AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self, model_class, stark_config=None): """ 注册表类 :param model_class: 表类class :param stark_config: 自定义配置 :return: """ if not stark_config: stark_config = StarkConfig self._registry[model_class] = stark_config(model_class, self) # 实例对象传参 """ { models.UserInfo: StarkConfig(models.UserInfo), # 封装:model_class=UserInfo,site=site对象 models.Role: RoleConfig(models.Role) # 封装:model_class=Role,site=site对象 } """ def get_urls(self): # 获取url urlpatterns = [] #url 列表 # urlpatterns.append(url(r'^x3/', ([ # url(r'^add/', self.x1), # url(r'^change/', self.x1), # url(r'^del/', self.x1), # url(r'^edit/', self.x1), # ],None,None))) for k, v in self._registry.items(): # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封装:model_class=UserInfo,site=site对象 # k=modes.Role,v=RoleConfig(models.Role) # 封装:model_class=Role,site=site对象 app_label = k._meta.app_label model_name = k._meta.model_name urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None))) # 表类所在app/表类名的组装 一个表类绑定的操作url return urlpatterns @property def urls(self): return self.get_urls(), self.app_name, self.namespace # url列表 # 返回的元组 site = AdminSite()
自定义思路
a.有自定义配置类的,重写继承的默认类变量,然后再由类方法自己去调用
b. 在自定义配置类,直接重写继承配置类的默认方法
1. 排序规则 2. 显示列 第一种方法: class UserInfoConfig(StarkConfig): list_display = ['id','title',StarkConfig.display_edit,StarkConfig.display_del] site.register(models.UserInfo,UserInfoConfig) 第二种方法: class UserInfoConfig(StarkConfig): order_by = ['-id'] def get_list_display(self): return ['id','title',StarkConfig.display_edit,StarkConfig.display_del]
3. 添加按钮 class UserInfoConfig(StarkConfig): list_display = ['id','title',StarkConfig.display_edit,StarkConfig.display_del] def get_add_btn(self): # 显示 # return mark_safe('<a href="%s" class="btn btn-success">添加</a>' % self.reverse_add_url()) # 不显示 return None site.register(models.UserInfo,UserInfoConfig)
4. 定制ModelForm 第一种方法: class DepartModelForm(forms.ModelForm): class Meta: model = models.Depart fields = "__all__" def clean_name(self): return self.cleaned_data['name'] class DepartConfig(StarkConfig): list_display = [StarkConfig.display_checkbox,'id', 'name', 'tel', 'user',StarkConfig.display_edit_del] model_form_class = DepartModelForm 第二种方法: class DepartModelForm(forms.ModelForm): class Meta: model = models.Depart fields = "__all__" def clean_name(self): return self.cleaned_data['name'] class DepartConfig(StarkConfig): list_display = [StarkConfig.display_checkbox,'id', 'name', 'tel', 'user',StarkConfig.display_edit_del] def get_model_form_class(self): return DepartModelForm
5. 自定义列表页面 class DepartConfig(StarkConfig): list_display = [StarkConfig.display_checkbox,'id', 'name', 'tel', 'user',StarkConfig.display_edit_del] model_form_class = DepartModelForm def changelist_view(self, request): return HttpResponse('自定义列表页面') site.register(models.Depart, DepartConfig) 6. 增加URL class RoleConfig(StarkConfig): order_by = ['-id', ] list_display = [StarkConfig.display_checkbox,'id','title',StarkConfig.display_edit,StarkConfig.display_del] def extra_url(self): data = [ url(r'^xxxxxxx/$', self.xxxxxx), ] return data def xxxxxx(self,request): print('....') return HttpResponse('xxxxx') site.register(models.Role,RoleConfig) 7. 自定制URL class RoleConfig(StarkConfig): order_by = ['-id', ] list_display = [StarkConfig.display_checkbox,'id','title'] def get_add_btn(self): return False def extra_url(self): data = [ url(r'^xxxxxxx/$', self.xxxxxx), ] return data def xxxxxx(self,request): print('....') return HttpResponse('xxxxx') def get_urls(self): info = self.model_class._meta.app_label, self.model_class._meta.model_name urlpatterns = [ url(r'^list/$', self.wrapper(self.changelist_view), name='%s_%s_changelist' % info), ] extra = self.extra_url() if extra: urlpatterns.extend(extra) return urlpatterns site.register(models.Role,RoleConfig)