Sansa组件
诉求
仿照admin组件,实现对表的URL分配管理。
实现思路
1.在settings.py文件中注册APP,注册示例为:
'app01.apps.App01Config',
'app02.apps.App02Config',
‘stark_demo.apps.StarkDemoConfig',
2. 在每一个APP中的apps.py 文件中添加
from django.apps import AppConfig
2 from django.utils.module_loading import autodiscover_modules class App01Config(AppConfig):
name = 'app01' 7 def ready(self):
8 autodiscover_modules('stark',)
实现在Django项目启动时,扫描每个APP项目下的stark.py文件的文件,执行其中的代码,注册每个APP下的model,为每一个model生成增删改查四条URL。
来一张流程图进行说明。
Starksite类和Modelstark类的创建
from django.conf.urls import url
from django.shortcuts import HttpResponse, render, reverse,redirect
from django.utils.safestring import mark_safe
from django.forms import ModelForm
from app01.models import *
from app02.models import * # 针对使用stark组件的默认样式类 class Modelstark(object):
list_display = ["__str__"]
list_display_link = ["__str__"]
model_form = None
# init 方法在实例化类的时候执行 def __init__(self, model, site):
self.model = model
self.site = site
self.label_model = (self.model._meta.app_label, self.model._meta.model_name)
'''
功能:
将显示、编辑、删除、增加页面的url 封装到函数中。
函数名:
def get_add_url(self)
def get_del_url(self,obj)
def get_edit_url(self,obj)
def get_list_url(self)
'''
def get_add_url(self):
add_url = reverse("%s_%s_add" % self.label_model, )
return add_url def get_del_url(self,obj):
del_url = reverse("%s_%s_del" % self.label_model, args=(obj.pk,))
return del_url def get_edit_url(self,obj):
edit_url = reverse("%s_%s_edit"% self.label_model,args=(obj.pk,))
return edit_url def get_list_url(self):
list_url = reverse("%s_%s_show"%self.label_model,)
return list_url
'''
功能:
为显示页面右侧的添加按钮生成动态的URL
函数名:
def add_btn(self,obj=None,header=False)
'''
def add_btn(self,obj=None,header=False):
if header:
pass
return mark_safe("<a href='%s' type='button' class='btn btn-success btn-lg pull-right'>添加</a>"%self.get_add_url())
'''
功能:
为显示页面生成编辑、删除和复选框的标签
函数名:
def edit(self,obj=None,header=False)
def delete(self,obj=None,header=False)
def checkbox(self,obj=None,header=False)
'''
def edit(self,obj=None,header=False):
if header:
return "操作"
return mark_safe("<a href='%s''>编辑</a>"%self.get_edit_url(obj)) def delete(self,obj=None,header=False):
if header:
return "操作"
return mark_safe("<a href='%s''>删除</a>" %self.get_del_url(obj)) def checkbox(self,obj=None,header=False):
if header:
return mark_safe("<input type='checkbox' id='action-toggle'>")
pass return mark_safe("<input type='checkbox' value='%s'>"%obj.pk) pass
'''
功能:
为每一个类生成modelform,用于渲染标签
判断用户是否定义了model_form,如果定义了则用用户自己的类,没有则用默认的modelForm
备注:
显示中文错误提示信息的解决思想是:
在样式类中定义一个 model_form = None 的静态变量,在 def default_modelform(self) 函数中判断 model_form = None的bool值,若为False,
则表明用户没有自定义 model_form ,因此走默认的modelForm.
若model_form 为True,则表明用户对要注册的表定义了modelForm,因此用户会在自己的 XXXConfig类中声明 model_form = 自定义的modelForm,
此时用用户自定义的 modelForm
函数名:
def mdelform(self)
'''
def default_modelform(self):
class modelForm(ModelForm):
class Meta:
model = self.model
fields = "__all__"
if not self.model_form:
return modelForm
else:
return self.model_form
'''
功能:
显示、编辑、增加、删除4个视图函数
函数名:
def show_list(self, request)
def add_list(self, request)
def edit_list(self, request,id)
def del_list(self, request,id)
'''
def show_list(self, request):
data_list = self.model.objects.all()
# 显示表头名称
header_list = []
for i in self.real_list_display():
if callable(i):
# 获取函数名:函数名.__name__
# header_list.append(i.__name__) -----> low版
header_list.append(i(self, header=True))
else:
if i == "__str__":
header_list.append(self.model._meta.model_name.upper())
else:
header_list.append(self.model._meta.get_field(i).verbose_name) # print(self.list_display)
# 首先循环每一条记录
"""
需要构建的样式为:
[
["id1","name1"],
["id2","name2"],
["id3","name3"],
]
"""
# 显示数据
ret_data_list = []
for obj in data_list:
tmp_list = []
# 遍历显示的字段,i 指的是字段名称
for i in self.real_list_display():
if callable(i):
val = i(self, obj)
else:
# val 为反射后的value
val = getattr(obj, i)
# 判断当前的 字段名称 是否在 list_display_link 中,在的话让该字段对应的值作为a标签
if i in self.list_display_link:
val = mark_safe("<a href='%s'>%s</a>"%(self.get_edit_url(obj),val))
tmp_list.append(val)
ret_data_list.append(tmp_list)
# 显示添加按钮
btn_list = []
# 使用类.函数 的方式需要传self,但是使用类的对象.方法的方式不需要传self
val = Modelstark.add_btn(self)
btn_list.append(val) return render(request, "show_list.html", locals()) def add_list(self, request):
modelForm = self.default_modelform()
errors = {}
if request.method == "POST":
form = modelForm(request.POST)
if form.is_valid():
form.save()
return redirect(self.get_list_url())
else:
return render(request,"add.html",locals())
form = modelForm()
return render(request,"add.html",locals()) def edit_list(self, request,id):
obj = self.model.objects.filter(id=id).first()
modelForm = self.default_modelform()
if request.method == "POST":
form = modelForm(request.POST,instance=obj)
if form.is_valid():
form.save()
return redirect(self.get_list_url())
else:
pass
form = modelForm(instance=obj)
return render(request,"edit.html",locals()) def del_list(self, request,id):
if request.method == "POST":
self.model.objects.filter(id=id).delete()
return redirect(self.get_list_url())
list_url = self.get_list_url()
return render(request,"delete.html",locals())
'''
功能:
在显示页面要真正显示的字段,对list_display进行扩展
函数名:
def real_list_display(self)
'''
def real_list_display(self):
new_list_display = []
new_list_display.extend(self.list_display)
new_list_display.append(Modelstark.edit)
new_list_display.append(Modelstark.delete)
new_list_display.insert(0,Modelstark.checkbox)
return new_list_display
'''
功能:
为没一个注册的model生成增删改查四条URL
函数名:
def get_url_func(self)
'''
def get_url_func(self):
tmp = []
app_name = self.model._meta.app_label
model_name = self.model._meta.model_name
ret = (app_name, model_name)
tmp.append(url("^$", self.show_list, name="%s_%s_show" %ret))
tmp.append(url("^add/$", self.add_list, name="%s_%s_add" %ret))
tmp.append(url("^edit/(\d+)/$", self.edit_list, name="%s_%s_edit" %ret))
tmp.append(url("^del/(\d+)/$", self.del_list, name="%s_%s_del" %ret))
'''
在访问URL之前就已经分别为每张表创建了4条URL
'''
return tmp # 创建stark类,实例化Starksite,用于注册model class Starksite(object): def __init__(self):
# 保存表的注册信息,保存的格式为:以model类为键,以该model实例化样式对象为值
self._registry = {} # 类的注册函数
def register(self, model, modelconfig=None):
'''
实现model的注册
:param model: 要注册的类
:param modelconfig: 该注册类的样式对象
:return: None
''' '''
判断用户是否自己定义了样式类,如果没有,此时的modelconfig为None,则用默认的ModelStark样式类进行实例化注册;
若用户自定义了注册类的样式对象,则使用用于自定的样式对象
'''
if not modelconfig:
modelconfig = Modelstark
# model是每次循环注册的表,self是实例化的Startksite类的实例化对象
'''
在对注册的model进行样式实例化的时候,modelconfig类实际上是Modelstark类的实例化,实例化要执行类的__init__函数,init函数的定义为:
def __init__(self, model, site):
self.model = model
self.site = site
self.label_model = (self.model._meta.app_label, self.model._meta.model_name)
此时实例化的方式为:类名.__init__() 方式,因此需要传self。
另外需要注意的是modelconfig(model,self)中的self是哪个类的实例化对象
当在注册类的时候没有传入制定的样式类,那么这里的self是Modelstark类的实例化,
但是,当用户传入定制的样式类时,此时的self是modelconfig类的实例化
'''
self._registry[model] = modelconfig(model, self) def get_urls(self):
'''
生成表的一级和二级URL
:return: tmp
'''
tmp = []
'''
item():使字典中的键值对以元组的形式显示
model: 注册的model类
model_config:该类对应的样式类对象
app_label:以字符串形式获取类所在的APP
model_name:以字符串的获取类名
'''
for model, model_config in self._registry.items():
app_label = model._meta.app_label
model_name = model._meta.model_name
# 为什么不能去掉None
u = url("^%s/%s/" % (app_label, model_name), (model_config.get_url_func(), None, None))
tmp.append(u)
return tmp
'''
把urls函数做成静态方法,urls.py 中执行urls函数不需要加()
'''
@property
def urls(self):
return self.get_urls(), None, None # 创建单例对象,在每一个app中的stark文件中调用
site = Starksite()
各功能的实现思路
一级与二级URL的设计思路
在注册完表后,执行urls.py文件,执行
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^stark/', site.urls),
]
site为类Starksite的单例实例化对象,site.urls 调用类下的urls方法,而urls方法实际上是执行get_urls(self) 方法,为每一个model首先生成一级URL,其次调用类的样式对象下的get_url_func(self)
函数,生成二级URL,同时为每一个增删改查URL创建别名,用于反向解析。
显示页面的数据显示
1.数据显示的思路
首先类中定义一个 list_display = ["__str__"]的静态变量,此静态变量在用于没有重写该变量时,则默认显示该对象的 def __str__(self) 方法的返回值。
将显示的数据以 [ [1,"python",12,"<a>编辑</a>"],[2,"java",23,"<a>编辑</a>"],[3,"php",111,"<a>编辑</a>"],]的形式在后后台处理成功后,循环判断要显示的数据是一个字符串还是可执行函数,若是可执行函数则执行函数后追加保存到列表中,若是字符串则直接追加保存在列表中。
PS:
1.getattr(obj,str) 函数用于反射,实现通过对象的字段名名称找到该字段对应的值。
2.要循环的字段实际上是new_list_display, 即对list_display进行扩展,是默认显示的字段有复选框、对象名称、编辑、删除
def real_list_display(self):
new_list_display = []
new_list_display.extend(self.list_display)
new_list_display.append(Modelstark.edit)
new_list_display.append(Modelstark.delete)
new_list_display.insert(0,Modelstark.checkbox)
return new_list_display
2.编辑和删除a标签的实现
把编辑和删除的a标签分别作为一个函数,使该函数的返回值为 mark_safe("<a>编辑</a>"),在循环要显示的字段对象的数据时,执行该函数。
PS:
mark_safe()函数实现前端safe相同的功能,使django不转移标签对象。
3.表头的实现
根据list_display 循环显示表头,当遇到“__str__”时,找到该该对象的“__str__“”方法的返回值,当遇到制定的字段名称,如public时,则使用 self.model._meta.get_field(i).verbose_name获取该字段的verbose_name,追加到列表中。
PS:
get_field(arg) 可以获取到model表中该arg字段对象,该对象可以调用字段的属性,如verbose_name。
4.让字段作为a标签,实现跳转到编辑页面的实现
在循环显示数据的时候, 判断通过getattr()方法获取的字段值是否在list_display_link中,如果在,则使用mark_safe()使该value成为a标签。
5. ModelForm 组件实现页面的增删改查
只需要为要进行form渲染的类继承ModelForm,即可。
6.使用ModelForm实现显示中文错误信息
在样式类中创建一个model_form = None的静态变量,在创建 ModelForm 类的函数 def default_modelform(self)中判断model_form的值,值为None,则使用默认的modelform,如果为True,则使用用户stark.py中定义的样式类。
在每个APP中stark.py文件的创建
from .models import *
# 对单例对象的调用
from stark_demo.service.sites import site,Modelstark
from django.forms import ModelForm class BookModelForm(ModelForm):
'''
重写model的modelform类
'''
class Meta:
model = Book
fields = "__all__"
error_messages = {
"title":{"required":"不能为空"},
"public":{"required":"不能为空"}
} class BookConfig(Modelstark): list_display = ["id","title","public"]
list_display_link = ["id","title",]
model_form = BookModelForm site.register(Book,BookConfig)
Sansa组件的更多相关文章
- Flask框架 之 第三方组件
浏览目录 flask-session flask-sqlalchemy flask-script flask-migrate flask-session 安装 pip3 install flask-s ...
- 第五篇 Flask组件之SQLAchemy及Flask-SQLAlchemy插件/Flask-Script/Flask-migrate/pipreqs模块
SQLAlchemy组件 一. 介绍 SQLAlchemy是一个基于Python实现的ORM框架.该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然 ...
- ExtJS 4.2 评分组件
上一文章是扩展ExtJS自带的Date组件.在这里将创建一个评分组件. 目录 1. 介绍 2. 示例 3. 资源下载 1. 介绍 代码参考的是 Sencha Touch 2上的一个RatingStar ...
- react组件的生命周期
写在前面: 阅读了多遍文章之后,自己总结了一个.一遍加强记忆,和日后回顾. 一.实例化(初始化) var Button = React.createClass({ getInitialState: f ...
- react-router 组件式配置与对象式配置小区别
1. react-router 对象式配置 和 组件式配置 组件式配置(Redirect) ----对应---- 对象式配置(onEnter钩子) IndexRedirect -----对应-- ...
- Angular2入门系列教程3-多个组件,主从关系
上一篇 Angular2项目初体验-编写自己的第一个组件 好了,前面简单介绍了Angular2的基本开发,并且写了一个非常简单的组件,这篇文章我们将要学会编写多个组件并且有主从关系 现在,假设我们要做 ...
- Angular2入门系列教程2-项目初体验-编写自己的第一个组件
上一篇 使用Angular-cli搭建Angular2开发环境 Angular2采用组件的编写模式,或者说,Angular2必须使用组件编写,没有组件,你甚至不能将Angular2项目启动起来 紧接着 ...
- .NET Core 首例 Office 开源跨平台组件(NPOI Core)
前言 最近项目中,需要使用到 Excel 导出,找了一圈发现没有适用于 .NET Core的,不依赖Office和操作系统限制的 Office 组件,于是萌生了把 NPOI 适配并移植到 .NET C ...
- .NetCore中的日志(1)日志组件解析
.NetCore中的日志(1)日志组件解析 0x00 问题的产生 日志记录功能在开发中很常用,可以记录程序运行的细节,也可以记录用户的行为.在之前开发时我一般都是用自己写的小工具来记录日志,输出目标包 ...
随机推荐
- CentOS7下BIND配置主从服务器和缓存服务器
系统环境:CentOS Linux release 7.4.1708 (Core) 3.10.0-693.el7.x86_64 软件版本:bind-chroot-9.9.4-51.el7_4.1.x ...
- CreateThread
CreateThread(NULL,0,ReportResultThread,this,0,&g_dwThreadId) 2. 参数说明: 第一个参数 lpThreadAttributes 表 ...
- hdu-1176(动态规划)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1176 思路:类似数塔问题, 从最后一秒开始考虑,每次这一秒的状态确定意味着前一秒的状态也已经确定,所以 ...
- hdu-1173(最短距离)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1173 思路:最短距离:就是现将x,y从小到大排序,然后去中间点就行了.(注意:本题答案不唯一) #in ...
- linux安装mysql~~~mysql5.6.12
Linux安装mysql服务器 准备: MySQL-client-5.6.12-1.rhel5.i386.rpm MySQL-server-5.6.12-1.rhel5.i386.rpm 首先检查环境 ...
- MATLAB实现截位的问题
讨论MATLAB怎样提取10进制中的位的方法,因为做FFT时要用到截位,相去验证它,向同庆请教, 原来只是除以2的N次方,取模取余就行了,可恨我还想了一下午,也没有一个好办法. 接下来的问题是,对于负 ...
- DIV+CSS实战(五)
一.说明 前面实现了关键词订阅模块,现在实现站点订阅模块,主要实现的是站点添加界面.站点添加界面里面实现一个提示框不在提示的功能(保存到cookie中),还有就是实现一个站点的选择框,包括输入文字自动 ...
- returning into 语句
returning into 语句用于执行完语句后返回的值,具体返回执行之前或者之后的结果,多用于在存储过程中 如下所述:delete语句的returning into语句返回的是delete之前的结 ...
- 反爬虫破解系列-汽车之家利用css样式替换文字破解方法
网站: 汽车之家:http://club.autohome.com.cn/ 以论坛为例 反爬虫措施: 在论坛发布的贴子正文中随机抽取某几个字使用span标签代替,标签内容位空,但css样式显示为所代替 ...
- Bezier曲线
1. 学习网址 http://give.zju.edu.cn/cgcourse/new/book/8.2.htm