诉求

  仿照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组件的更多相关文章

  1. Flask框架 之 第三方组件

    浏览目录 flask-session flask-sqlalchemy flask-script flask-migrate flask-session 安装 pip3 install flask-s ...

  2. 第五篇 Flask组件之SQLAchemy及Flask-SQLAlchemy插件/Flask-Script/Flask-migrate/pipreqs模块

    SQLAlchemy组件 一. 介绍 SQLAlchemy是一个基于Python实现的ORM框架.该框架建立在 DB API之上,使用关系对象映射进行数据库操作,简言之便是:将类和对象转换成SQL,然 ...

  3. ExtJS 4.2 评分组件

    上一文章是扩展ExtJS自带的Date组件.在这里将创建一个评分组件. 目录 1. 介绍 2. 示例 3. 资源下载 1. 介绍 代码参考的是 Sencha Touch 2上的一个RatingStar ...

  4. react组件的生命周期

    写在前面: 阅读了多遍文章之后,自己总结了一个.一遍加强记忆,和日后回顾. 一.实例化(初始化) var Button = React.createClass({ getInitialState: f ...

  5. react-router 组件式配置与对象式配置小区别

    1. react-router 对象式配置 和 组件式配置    组件式配置(Redirect) ----对应---- 对象式配置(onEnter钩子) IndexRedirect -----对应-- ...

  6. Angular2入门系列教程3-多个组件,主从关系

    上一篇 Angular2项目初体验-编写自己的第一个组件 好了,前面简单介绍了Angular2的基本开发,并且写了一个非常简单的组件,这篇文章我们将要学会编写多个组件并且有主从关系 现在,假设我们要做 ...

  7. Angular2入门系列教程2-项目初体验-编写自己的第一个组件

    上一篇 使用Angular-cli搭建Angular2开发环境 Angular2采用组件的编写模式,或者说,Angular2必须使用组件编写,没有组件,你甚至不能将Angular2项目启动起来 紧接着 ...

  8. .NET Core 首例 Office 开源跨平台组件(NPOI Core)

    前言 最近项目中,需要使用到 Excel 导出,找了一圈发现没有适用于 .NET Core的,不依赖Office和操作系统限制的 Office 组件,于是萌生了把 NPOI 适配并移植到 .NET C ...

  9. .NetCore中的日志(1)日志组件解析

    .NetCore中的日志(1)日志组件解析 0x00 问题的产生 日志记录功能在开发中很常用,可以记录程序运行的细节,也可以记录用户的行为.在之前开发时我一般都是用自己写的小工具来记录日志,输出目标包 ...

随机推荐

  1. Linux 配置文件管理

    一.简介 参考:https://robots.thoughtbot.com/rcm-for-rc-files-in-dotfiles-repos http://dotfiles.github.io/ ...

  2. doctotext

    文档解析库 http://www.it610.com/article/1936051.htm

  3. swift 设置string 中汉字中变色等处理代码

    我们在做弹窗 或者显示label string的时候经常会用到字体变色 变大 等特殊处理, swift中提供一个函数 NSMutableAttributedString 使用方法简介 var main ...

  4. Tomcat连接池配置

    今日做了个小网站,数据量不大,但当发布到虚拟主机上之后,接连不断的遇到各种问题. 被折磨了数日后,在网上查了大量的相关资料,现总结如下. 一.项目在上传到远程服务器的过程中,有可能丢失文件,或文件内容 ...

  5. ELMAH 使用

    之前大部分系统日志记录是使用log4net.ObjectGuy Framework.NLog 等工具记录到文本或数据库. 更强大的工具可以使用 ELMAH. ELMAH(The Error Loggi ...

  6. 2018.08.27 [Usaco2017 Jan]Promotion Counting(线段树合并)

    描述 The cows have once again tried to form a startup company, failing to remember from past experienc ...

  7. 【Unity】2.2 Unity编辑器中的常用菜单项

    分类:Unity.C#.VS2015 创建日期:2016-03-26 Unity 5.3.4编辑器共提供了7个主菜单项,这一节主要学习其中的常用项. 一.File 1.基本功能 New Scene:新 ...

  8. hadoop学习笔记(四):hdfs常用命令

    一.hadoop fs 1.创建目录 [root@master hadoop-]# hadoop fs -mkdir /testdir1 [root@master hadoop-]# hadoop f ...

  9. 解决Web Uploader上传文件和图片 延迟和not defined

    1.出现list not define时,var $list = $("#fileList"); 2.选择文件框有延迟,可能是因为选择文件类型过多 mimeTypes: 'imag ...

  10. SSH整合 第四篇 Spring的IoC和AOP

    这篇主要是在整合Hibernate后,测试IoC和AOP的应用. 1.工程目录(SRC) 2.IoC 1).一个Service测试类 /* * 加入spring容器 */ private Applic ...