python Stark 组件
Django Admin 是对model中 对应的数据表进行增删改查的组件,对每个APP下面已注册的model表进行增删改查。而stark组件仿照Admin组件开发。
Admin的常用配置:
Filedstes
使用方法和效果如下图
Action
使用方法和效果图
需要在My_AppConfig(admin.ModeAdmin)中编写自定义函数
需要注意的:(1)该函数在select下拉框中 作为value值
(2)该函数有两个参数,分别是request、queryset
(3)前端的复选框,前端整合成一个字典。字典的键:复选框的name,字典的值:列表类型,存储valu
定义的foo会在前端action的select 下拉框,函数名当作value值
Admin 的使用两个场景:
1)admin 配置url
2)注册model
注意:每个APP下有个admin模块
使用流程
1、当django项目启动时,admin应用首先扫描(加载)每个APP下面的每个admin.py 文件
自执行函数,autodiscover()执行扫描,扫描
2、每个admin文件导入admin模块时,生成site对象、
3、使用site对象注册model 中的类名
4、生成已注册model类的增删改查url
知识点:
1、同一模块重复调用,文件只加载一次
2、基于模块的单例模式,第一次生成对象时,会生成一个内存空间_instance,当第二次生成时,_instance有值,会把该对象的内存指向上一次对象的内存空间
路由分发
一条url有正则和相对应的函数组成,路由分发则是把对应的函数转变成一个元组。元组包括一个列表,和两个None值
仿照admin开发的过程中,目的是生成model对应的url,需要获取该model所在APP的名字和mode的名字.
使用my_model._meta.model_name 获取
自定义stark组件仿照admin:注意,在stark apps.py 配置文件中的类中,增加一个函数
def ready(self):autodiscover_modules("stark_admin")
该函数的意义:——执行文件下的read方法——扫描startk文件
注意:static 放在项目下面,需配置staticfiles 放在应用下面,无须配置。django扫描每个项目下面的static文件
admin的两个类
Starksit ModelStark ,前者负责生成一级路由,后者生成二级路由。而且后者负责增删改查的功能。首先看下stark 组件主要有哪些功能:1)路由分发,涉及到两个类,就是刚才提到的。2)路由分发、action、edit_filter、list_filter、list_display、model_form_class(根据表名生成的表单)、list_display_link、search_fields 、下面详细介绍各个部分。
路由分发
StarkSite 部分
class StarkSite(object):def __init__(self):self._registry ={}def register(self,model,model_config=None):if not model_config:model_config = ModelStarkself._registry[model]=model_config(model,self)def get_urls(self):tmp = []for model,model_config in self._registry.items():model_name = model._meta.model_nameapp_name = model._meta.app_labelu = url('^{model_name}/{app_name}/'.format(model_name=model_name,app_name=app_name),(model_config.urls,None,None)) #设置路由分发 tmp.append(u)return tmp@propertydef urls(self):return self.get_urls(),None,Nonesite = StarkSite()
ModelStark部分
class ModelStark(object): #设计二级分发urldef get_urls(self):"""如何避免model_stark url下面的每个model产生相同的url:return: 二级分发的url"""tmp = []model_name = self.model._meta.model_name //获取model的名称app_name = self.model._meta.app_label //获取model所在APP的名字app_model = (app_name,model_name)tmp.append(url('^$', self.show_list,name="%s_%s_show_list"%app_model)) /避免model_stark url下面的每个model产生相同的urltmp.append(url('^(\d+)/change/$', self.change_view,name="%s_%s_change"%app_model))tmp.append(url('^add/$', self.add_view,name="%s_%s_add"%app_model))tmp.append(url('^(\d+)/delete/$', self.delete_view,name="%s_%s_delete"%app_model))return tmp@propertydef urls(self):return self.get_urls()
url的注意地方:
1)StarkSite urls函数返回的是一个元组,包括url列表 和APP的名字
2)url的软编码:获取增删改查相对应的软编码,reverse 的使用方法
reverse("%s_%s_delete" % self.app_model_name, args=(obj.pk,))
list_display && edit_filter
list_dispaly 是显示在前端的字段,用户可以自定义,否则,显示默认字段。这样ModelStark需要一个默认字段,list_display=['__str__']。这样在循环用户的list_display列表时,如果用户没有定义,就会遇到“__str__”字段,代表显示一个model的表头名称。由于在ModelStark的show_list 方法中显示前端数据封装至一个ChangeList方法中。ChangeList方法初始化时需要传入三个参数(config,request,queryset)分别代表Model_stark的对象,request请求,queryset是查询的数据,后面其他功能使用到。list_display 中可以添加一个函数名。
前端显示数据分为两个步骤:
ModelConfig 的show_list 显示头部、body 部分封装至一个类中,ChangeList中
1)列表body head的代码如下
class ChangeList(object):"""封装了查看视图的方法"""def __init__(self,config,request,queryset):self.config = config #相当于modelstark的本身self.request = request #每个ChangeList都有一个requestself.queryset =querysetparams = self.request.GETpage_num = self.request.GET.get("page", 1)total_count = self.queryset.count()base_url = request.path_infoself.pagination = Pagination(page_num, total_count, base_url, params)self.obj_list = self.queryset[self.pagination.start:self.pagination.end]self.actions = self.config.get_action()self.list_filter = self.config.list_filterdef heard(self): #获取头部信息header_list = []for filed in self.config.get_list_display():if callable(filed):var = filed(self, is_header=True) #头部信息,is_hearder设置为True,函数返回函数名称 header_list.append(var)else:if filed == "__str__": #如果是__str__字段就获取该model对象的名称header_list.append(self.config.model._meta.model_name.upper())#该字段的名字大写else:filed_obj = self.config.model._meta.get_field(filed)#获取该字段的对象header_list.append(filed_obj.verbose_name)#获取该字段的名字return header_listdef body(self):new_data_list = []for obj in self.obj_list:tem = []for filed in self.config.get_list_display():if callable(filed):val = filed(self.config, obj)else:val = getattr(obj, filed)if filed in self.config.list_display_link:val = self.config.get_link_tag(self.request, obj, val)#这里传入的self.request 是ModelConfig实例对象 tem.append(val)new_data_list.append(tem)return new_data_list#右侧定义过滤字段def get_filter_link_tage(self):"""显示遍历用户定义的filter 列表,找到每个filter 字段,然后获取该字段对象,然后把该对象字段传入自己创建的类中,获取该字段所有的对象。再次for循环通过该字段获取的所有对象,循环过程中,传入外层for循环的字段对象,判断该对象的字段类型,然后返回该对象的a标签,该标签的href包含该对象的字段名称和该对象的id:return:"""for filter_field_name in self.list_filter: ##list_filter = ["state","publish","authors"]遍历用户定义的字段print("filter_field_name",filter_field_name)current_id = int(self.request.GET.get(filter_field_name,0)) #获取前端的url后缀参数print("current_id",current_id)filter_field_obj = self.config.model._meta.get_field(filter_field_name)#获取该字段对象print("filter_field_obj",filter_field_obj)filter_field = FilterField(filter_field_name,filter_field_obj)#创建字段对象print("*"*120,filter_field)def inner(filter_field,current_id):for obj in filter_field.get_data():if isinstance(filter_field.filter_field_obj,ForeignKey) or isinstance(filter_field.filter_field_obj,ManyToManyField):params = copy.deepcopy(self.request.GET)params._mutable = Trueparams[filter_field.filter_field_name] = obj.pkif obj.pk== current_id:yield mark_safe("<a class='active' href='?%s'>%s<a>"%(params.urlencode(),obj))else:yield mark_safe("<a href='?%s'>%s</a>"%(params.urlencode(),obj))elif filter_field.filter_field_obj.choices:params = copy.deepcopy(self.request.GET)params._mutable = Trueparams[filter_field.filter_field_name] = obj[0]if current_id ==obj[0]:yield mark_safe("<a class='active' href='?%s'>%s</a>"%(params.urlencode(),obj[1]))else:yield mark_safe('<a href="?%s">%s</a>'%(params.urlencode(),obj[1]))else:passyield inner(filter_field,current_id)
View Code
2)上图用到的get_list_display()方法如下:主要作用是把用户自定义和ModelConfig 中的list_display合并,给所有数据默认添加一个 编辑,删除 字段
# 封装list_display方法def get_list_display(self):new_list_display = []new_list_display.extend(self.list_display)if not self.list_display_link: # 如果用户没有定义超链接字段,就添加编辑字段。超链接字段和可编辑字段显示一个就可以 new_list_display.append(ModelStark.edit)new_list_display.append(ModelStark.delete)new_list_display.insert(0, ModelStark.check_box)return new_list_display
get_list_display
3)用的编辑、删除、添加字段
#编辑按钮def edit(self, obj=None, is_header=False):if is_header:return "编辑"return mark_safe("<a href='%s'>编辑</a>" % self.edit_url(obj))# 删除按钮def delete(self, obj=None, is_header=False):if is_header:return "删除"# 如何反向解析urlreturn mark_safe("<a href='%s'>删除</a>" % self.delete_url(obj))#添加按钮def add(self, obj=None, is_header=False):if is_header:return "添加"return mark_safe("<a href='%s'>添加</a>" % self.add_url())
View Code
4)生成表头是用到callable,判断是否为一个函数。下面是编辑、删除按钮的函数,表头显示,传入heard参数。
#编辑按钮def edit(self, obj=None, is_header=False):if is_header:return "编辑"return mark_safe("<a href='%s'>编辑</a>" % self.edit_url(obj))# 删除按钮def delete(self, obj=None, is_header=False):if is_header:return "删除"# 如何反向解析urlreturn mark_safe("<a href='%s'>删除</a>" % self.delete_url(obj))#添加按钮def add(self, obj=None, is_header=False):if is_header:return "添加"return mark_safe("<a href='%s'>添加</a>" % self.add_url())
View Code
5)再次判断该字段是否是一个超链接字段
if filed in self.config.list_display_link:val = self.config.get_link_tag(self.request, obj, val)#这里传入的self.request 是ModelConfig实例对象
超链接字段url后缀(list_filter),在跳转时可以记录上次的url后缀。下面代码设置超链接字段
#编辑字段设置url后缀def get_link_tag(self,request, obj, val):""":param request::param obj::param val::return:返回一个带有?list_fileter后缀的"""params = request.GETimport copyparams = copy.deepcopy(params)params._mutable = Truefrom django.http import QueryDictquery_dict = QueryDict(mutable=True)query_dict["list_filter"] = params.urlencode() # qd: {"list_filter":"a%21341%1234b%21322"} suffix_url = mark_safe("<a href='%s?%s'>%s</a>" % (self.edit_url(obj), query_dict.urlencode(), val))#跳转时保存上次的urlreturn suffix_url
get_link_tag
model_form_class
添加 编辑用到的modelform
思路设计:ModeForm 设置一个属性(model_form_class),判断用户是否定义了该属性,如果没有定义使用自身的ModeForm
#设置ModelFormdef get_model_form(self):from django.forms import ModelFormfrom django.forms import widgetsclass ModelFormClass(ModelForm):class Meta:model = self.modelfields = "__all__"if not self.model_form_class:return ModelFormClasselse:return self.model_form_class
ModelForm
URL 对应的添加、编辑视图函数使用到ModeForm,两个视图函数如下。功能:提供表单
# 编辑视图函数def change_view(self,request,id):ModelFormClass = self.get_model_form()obj = self.model.objects.filter(id=id)[0]if request.method=="POST":form= ModelFormClass(request.POST,instance=obj)if form.is_valid():form.save()params =request.GET.get("list_filter")url = "%s?%s"%(self.show_list_url(),params) #这里传入page,视图函数可以需要根据当前页码来生成数据return redirect(url)else:return render(request, "stark/change.html", {"form": form})form = ModelFormClass(instance=obj)return render(request,"stark/change.html", locals())# 添加视图函数def add_view(self,request):ModelFormClass =self.get_model_form()if request.method=="POST":form= ModelFormClass(request.POST)if form.is_valid():form.save()return redirect(self.show_list_url())else:return render(request, "stark/add.html", locals())form = ModelFormClass()add_url = self.add_url()return render(request,"stark/add.html", locals())
编辑、添加视图函数
注意:1)编辑函数,取出url后缀。跳转url需要添加 刚才取到的页码参数,此时传送的page 会在ChangeList类中使用到
页面状态保留
search_fields
#查询函数def search_fucn(self):search_condition = Q()if self.search_fields:#如果用户配置了筛选字段search_condition.connector = 'or' #查询:q的两个条件是“or”的关系search_keyword = self.request.GET.get("search")if search_keyword:for search_field in self.search_fields:search_condition.children.append((search_field+"__contains", search_keyword))return search_condition #如果没有查询条件返回空的Q,
show_list函数:前端提交查询,为GET方式
Action
action和之前定义的list_display等一样,同样的需要在 ModelConfig 中定义一个默认的action。ModelConfig的默认action中包含一个delete函数
#前端删除hansdef patch_delete(self,queryset):queryset.delete()return Truepatch_delete.desc = "批量删除" //函数对象设置一个desc属性#用户的actiondef get_action(self):temp = []temp.extend(self.action)temp.append(ModelStark.patch_delete)return temp
ModelStark & action
上面的代码,把用户自定义和默认的action综合一起,但是在前端不能直接循环取得函数的属性,所以在ChangeList类中重新构建action的数据结构
class ChangeList(object):"""封装了查看视图的方法"""def __init__(self,config,request,queryset):、、、、self.actions = self.config.get_action()、、、、#action 数据结构def handle_actions(self):tmp=[]for action_func in self.actions:tmp.append({"name":action_func.__name__,"desc":action_func.desc})return tmp #在前端可以去到函数名和函数属性
View Code
前端批量选择对象时,触发刚才的action函数,这时show_list 以“POST”方式接受。
# 显示数据列表def show_list(self,request):self.request =request #这里的self.request 是在查询函数中使用,没有这个将会报错if request.method == "POST":func_name = request.POST.get("action",1)pk_list = request.POST.getlist("_selected_action")queryset = self.model.objects.filter(pk__in=pk_list)func = getattr(self,func_name)ret = func(queryset)if ret:return HttpResponse("OK")else:return HttpResponse("失败")
View Code
Filter
filter 功能,需要用户自定义过滤字段,否则不显示该功能。在ModelStark中 list_filter 默认为空的列表。
list_filter中存放的使用户想在前端展示的过滤字段如:
list_filter = ["state","publish","authors"]
下面介绍展示每个字段经历的过程:
这里需要用到一个参数两个类。ChangeList下的 get_filter_link_tage_two 函数。FilterField 类 、LinkTagGen类
get_filter_link_tage_two负责:循环listfilter中的用户定义字段,调用 FilterField、LinkTagGen 类
# 右侧定义过滤字段--第二版def get_filter_link_tage_two(self):for filter_field_name in self.list_filter: #list_filter = ["state","publish","authors"]遍历用户定义的字段 filter_field_obj = self.config.model._meta.get_field(filter_field_name) # 获取该字段对象 filter_field = FilterField(filter_field_name, filter_field_obj, self.config) # 创建字段对val = LinkTagGen(filter_field.get_data(), filter_field, self.request)#参数分别是:字段对象的所有数据,字段对象,requestyield val
View Code
注意:使用get_field 获取字段对象。然后把字段对象、字段名称传入FilterField, 获得该对象的数据。FilterField产生的数据,放入LinkTagGen 类中。LinkTagGen根据数据类型生成a标签
FilterField
class FilterField(object):def __init__(self, filter_field_name, filter_field_obj, config):self.filter_field_name = filter_field_name #字段名称self.filter_field_obj = filter_field_obj #字段对象self.config = config #相当于modelstark的本身def get_data(self):if isinstance(self.filter_field_obj, ForeignKey) or isinstance(self.filter_field_obj, ManyToManyField):return self.filter_field_obj.rel.to.objects.all()[:3]elif self.filter_field_obj.choices:return self.filter_field_obj.choiceselse:return self.config.model.objects.values_list("pk", self.filter_field_name)
获取字段对象的数据
FilterField,字段对象的所有数据,字段对象,传送给LinkTagGen类
LinkTagGen
该类定义了一个iter 方法。该方法的作用:迭代的返回一个数据,节省内存资源。
iter 生成标签,循环字段对象的所有数据。根据字段的类型判断是否加active,以及把上一次的url后缀保存下来
class LinkTagGen(object):def __init__(self, data, filter_field, request):self.data = dataself.fiter_field = filter_fieldself.request = requestdef __iter__(self):current_id = self.request.GET.get(self.fiter_field.filter_field_name, '0')params = copy.deepcopy(self.request.GET)params._mutable = Trueif params.get(self.fiter_field.filter_field_name): # 如果有值说明我是点击其他的按钮,“全部“按钮就没有必要加后缀del params[self.fiter_field.filter_field_name]_url = "%s?%s" % (self.request.path_info, params.urlencode())yield mark_safe("<a href='%s'>全部</a>" % _url)else:yield mark_safe("<a class='active' href='#'>全部</a>")for item in self.data:pk, obj = None, Noneif isinstance(self.fiter_field.filter_field_obj, ForeignKey) or isinstance(self.fiter_field.filter_field_obj, ManyToManyField):pk, obj = str(item.pk), itemelif self.fiter_field.filter_field_obj.choices:pk, obj = str(item[0]), item[1] #注意这里需要转换数据类型else:pk, obj =item[1], item[1]params[self.fiter_field.filter_field_name] = pk_url = "%s?%s" % (self.request.path_info, params.urlencode())if current_id == pk:link_tage = "<a class='active' href='%s'>%s</a>" % (_url, obj)else:link_tage = "<a href='%s'>%s</a>" % (_url, obj)yield mark_safe(link_tage)
View Code
阿萨德发
2、
转载于:https://www.cnblogs.com/huyangblog/p/8590682.html
python Stark 组件相关推荐
- python 全栈开发,Day112(内容回顾,单例模式,路由系统,stark组件)
python 全栈开发,Day112(内容回顾,单例模式,路由系统,stark组件) 一.内容回顾 类可否作为字典的key 初级 举例: class Foo(object):pass_registry ...
- Stark 组件:快速开发神器 —— 自动生成 URL
说道 Stark 你是不是不会想到他--Tony Stark,超级英雄钢铁侠,这也是我的偶像. 不过我们今天要开发的 Stark 组件,倒是跟他的人工智能助手 JARVIS 有些类似,是帮助我们快速开 ...
- Django基于admin的stark组件创建(一)
首先创建一个名为stark_test的Django项目,创建2个app一个名为app01用来测试stark组件,一个就叫做stark,用来放stark组件 如图: 我们这里使用的是Django自带的数 ...
- Django——stark组件
stark组件是仿照django的admin模块开发的一套组件,它的作用是在网页上对注册的数据表进行增删改查操作. 一.配置 1.创建stark应用,在settings.py中注册stark应用 st ...
- Django之stark组件1
stark组件 stark组件是根据Django admin为原型写的一个组件,能够让我们告别增删改查.stark组件是可插拔试的组件, 移植性强,而且只用配置文件就能够得到想要的数据 一.stark ...
- Stark 组件:快速开发神器 —— 锦上添花
Stark 组件:快速开发神器 -- 锦上添花 一.分页 二.排序 三.搜索 1.关键字搜索 2.组合搜索 四.批量操作 经过前面几个篇章,我们的 Stark 组件已经能够批量生成 URL,快速实现增 ...
- Stark 组件:快速开发神器 —— 页面显示
说道 Stark 你是不是不会想到他--Tony Stark,超级英雄钢铁侠,这也是我的偶像. 不过我们今天要开发的 Stark 组件,倒是跟他的人工智能助手 JARVIS 有些类似,是帮助我们快速开 ...
- Stark 组件:快速开发神器 —— 模板设计
说道 Stark 你是不是不会想到他--Tony Stark,超级英雄钢铁侠,这也是我的偶像. 不过我们今天要开发的 Stark 组件,倒是跟他的人工智能助手 JARVIS 有些类似,是帮助我们快速开 ...
- crm——stark组件核心原理
关于stark组件的简要介绍: 启动后.路由加载前定制一段代码. a. 创建一个 stark app 组件 b. 编写ready方法 1 from django.apps import AppCon ...
最新文章
- OpenCASCADE:Modeling Data之3D几何
- Atitit. Atiposter 发帖机 新特性 poster new feature v7 q39
- c均值算法的设计与实现_如何使用C链表实现 LRU 算法
- BZOJ 3223: Tyvj 1729 文艺平衡树-Splay树(区间翻转)模板题
- JAVAWEB入门tomcat服务器配置
- Keil | 解决Keil与VScode配合使用时,代码与注释位置不一样的问题。
- 案例 员工信息维护系统 c# 1613925570
- 东山再起?这将是锤子新手机?或搭配全键盘...
- CakePHP中文手册【翻译】
- Hyperledger Fabric服务器配置及修改Docker容器卷宗存储根目录/位置
- 函数式编程(Functional Programming)
- 宝塔linux搭建环境注意事项
- 当磁盘工具无法修复磁盘时,你可以这样做!
- 基于Windows 7环境的WAPI无线网络应用层控制实现
- 整篇文章翻译软件对接谷歌等各大翻译平台
- 江苏省淮安市谷歌高清卫星地图下载
- 教你用安卓神器-APK编辑器(手机端)改程序名+去程序广告!
- 如何用ppt做自我介绍
- LeetCode-Python-274. H指数
- phpmywind最新版sql注入以及后台目录遍历和文件读取
热门文章
- Linux oci连接oracle服务器
- 学习Flash制作高射炮游戏
- idea 彩虹屁合并语音包,语音包无法使用 解决教程
- RN cannot add a child that doesnot have a YogoNode to a parent without a measure function!
- 计算机无法登陆账户 让注销,电脑开机出现登陆账户,点了以后就马上注销,怎么处理?...
- 组合两个表(外连接的使用)
- C/C++订餐管理系统
- 咱们的课程里,有微信的这种菜单示例吗?---酷课堂iOS交流群问答整理(201810期)...
- Go学习笔记 -- 通道实现协程等待
- 使用WinDbg —— .NET篇 (一)