标签:单例模式 cond end 功能实现 ppc xxxx 渲染 serve get
? stark组件,是一个帮助开发者快速实现数据库表的增删改查。
? 10s 钟完成一张表的增删改查
Django 启动时,在执行 url.py之前执行一个指定程序
# 在已注册的APP中 app.py 里面
# django 内部有两个线程在运行,一个是运行Django,一个是检测代码是否发生变化
#runserver --norload 不启动检测线程
class appconfig(appconfig):
name = ‘app‘
def ready(self):
# 路由加载之前 在已注册的所有APP中自动寻找xxxx.py文件,并导入
# 如果执行两次,是因为Django内部自动重启导致
autodiscover_modules("xxxx")
# 提示:
如果xxxx.py 执行的代码向“某个神奇的地方”放入了一些值,之后的路由加载时,可以去‘某个神奇的地方‘读取原理的值
一个实例,一个对象
# 多实例
class foo(object):
pass
obj1 = foo()
print(obj1) #<__main__.foo object at 0x02B9E670>
obj2 = foo()
print(obj2) #<__main__.foo object at 0x02B9E538> 这是两个实例
通过python 模块导入的方式,实现单例模式
xx.py
class AdminSite(object):
pass
site = AdminSite() # 为AdminSite类创建了一个对象(实例)
app.py
import utils
print(utils.site)
import utils
print(utils.site)
"""
在Python中,如果已经导入过的文件再次被重新导入时候,python不会再重新解释一遍,而是选择从内存中直接将原来导入的值拿来用。
"""
补充
?
方式一
from django.conf.urls import url,include
urlpatterns = [
url(url(r‘^web/‘, include(‘app01.urls‘)),
# include 返回一个元组 (urlconf_module, app_name, namespace))
]
方式二
# include 函数主要返回有三个元素的元组
from django.conf.urls import url,include
from app01 import urls
urlpatterns = [
url(r‘^web/‘, (urls, app_name, namespace)),
]
app01/models.py
部门表
用户表
app02/models.py
主机表
为每张表创建4个url
为每张表创建4个视图函数
# 避免url重复,默认以应用名为开头
app01/models.py
Depart
/app01/depart/list/
/app01/depart/add/
/app01/depart/edit/(\d+)/
/app01/depart/del/(\d+)/
UserInfo
/app01/userinfo/list/
/app01/userinfo/add/
/app01/userinfo/edit/(\d+)/
/app01/userinfo/del/(\d+)/
app02/models.py
Host
/app02/host/list/
/app02/host/add/
/app02/host/edit/(\d+)/
/app02/host/del/(\d+)/
# v1.py
class StarkSite(object):
def __init__(self):
self._registry = []
self.app_name = ‘stark‘
self.namespace = ‘stark‘
def register(self, model_class, handler_class):
"""
:param model_class: 是models中的数据库表对应的类。 models.UserInfo
:param handler_class: 处理请求的视图函数所在的类
:return:
"""
self._registry.append({‘model_class‘: model_class, ‘handler‘: handler_class(model_class)})
def get_urls(self):
patterns = []
for item in self._registry:
model_class = item[‘model_class‘]
handler = item[‘handler‘]
app_label, model_name = model_class._meta.app_label, model_class._meta.model_name
# model_class._meta.app_label 获取models类所在的app名称
# model_class._meta.model_name 获取models类的名称
# patterns.append(url(r‘x1/‘,lambda request:HttpResponse("1")),)
patterns.append(url(r‘%s/%s/list/$‘ % (app_label, model_name,), handler.changelist_view))
patterns.append(url(r‘%s/%s/add/$‘ % (app_label, model_name,), handler.add_view))
patterns.append(url(r‘%s/%s/change/(\d+)/$‘ % (app_label, model_name,), handler.change_view))
patterns.append(url(r‘%s/%s/del/(\d+)/$‘ % (app_label, model_name,), handler.change_view))
return patterns
@property
def urls(self):
return self.get_urls(), self.app_name, self.namespace
site = StarkSite()
#url.py
from django.contrib import admin
from django.urls import path
from stark.service.v1 import site
print(site._registry)
urlpatterns = [
path(‘admin/‘, admin.site.urls),
path(‘^stark/‘, site.urls), #(site.get_urls(), site.app_name, site.namespace)
]
URL分发扩展&后缀
为url设置别名
url的别名进行重新生成
基本列表页面的定制
未定义list_display字段的页面,默认显示对象
class StarkHandler(object):
list_display = []
def changelist_view(self, request):
if list_display:
for i in list_display:
pass
else:
pass
为页面显示的列预留一个钩子函数
class StarkHandler(object):
list_display = []
def get_list_display(self):
value = []
value.extend(self.list_display)
return value
def changelist_view(self, request):
list_display = self.get_list_display()
if list_display:
for i in list_display:
pass
else:
pass
为页面提供自定义显示的函数
v1.py
class StarkHandler(object):
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_change_url_name,)
return mark_safe(‘<a href="%s">编辑</a>‘ % reverse(name, args=(obj.pk,)))
# 根据名称空间,别名,反向生成url
def display_del(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 changelist_view(self, request):
if list_display:
for key_or_func in list_display:
if isinstance(key_or_func, FunctionType):
# key_or_func虽然本来是hander中的方法,
#但在传入时是以函数传入的,所以要把self也传入
verbose_name = key_or_func(self, obj=None, is_header=True)
else:
verbose_name = self.model_class._meta.get_field(key_or_func).verbose_name
header_list.append(verbose_name)
stark.py
from stark.service.v1 import site, StarkHandler,get_choice_text
class UserInfoHandler(StarkHandler):
list_display = [‘name‘,
‘age‘, ‘email‘, ‘depart‘,
StarkHandler.display_edit,
StarkHandler.display_del]
site.register(models.UserInfo,UserInfoHandler)
应用
如何显示添加按钮
如何添加按钮的url
from django.http import QueryDict
import functools
class StarkHandler(object):
list_display = []
def __init__(self, site, model_class, prev):
self.site = site
self.model_class = model_class
self.prev = prev
self.request = None
self.has_add_btn = True # 默认要显示添加按钮
def reverse_add_url(self):
"""
生成带有原搜索条件的添加URL
:return:
"""
name = "%s:%s" % (self.site.namespace, self.get_add_url_name,)
base_url = reverse(name)
if not self.request.GET:
add_url = base_url
else:
param = self.request.GET.urlencode()
new_query_dict = QueryDict(mutable=True)
new_query_dict[‘_filter‘] = param
add_url = "%s?%s" % (base_url, new_query_dict.urlencode())
return add_url
def get_add_btn(self):
# 返回添加按钮,href 通过 reverse_add_url()获得反向生成的url
if self.has_add_btn:
# 判断是否要显示添加按钮
return "<a class=‘btn btn-primary‘ href=‘%s‘>添加</a>"
% self.reverse_add_url()
return None
def changelist_view(self, request):
add_btn = self.get_add_btn()
return render(request,‘stark/changelist.html‘,
{‘add_btn‘: add_btn,})
def wrapper(self, func):
@functools.wraps(func)
# @functools.wraps 保留原函数的参数信息
def inner(request, *args, **kwargs):
# 通过装饰器,使每一个请求进入视图函数后都能保存自己的request
self.request = request
return func(request, *args, **kwargs)
return inner
def get_urls(self):
patterns = [
url(r‘^list/$‘, self.wrapper(self.changelist_view), name=self.get_list_url_name),
url(r‘^add/$‘, self.wrapper(self.add_view), name=self.get_add_url_name),
url(r‘^change/(?P<pk>\d+)/$‘, self.wrapper(self.change_view), name=self.get_change_url_name),
url(r‘^delete/(?P<pk>\d+)/$‘, self.wrapper(self.delete_view), name=self.get_delete_url_name),
]
patterns.extend(self.extra_urls())
return patterns
添加页面进行添加数据
可以添加显示的字段,接口供用户扩展
需求 :少显示字段,保存时,减少的字段也得设置,否则存储出错
from django import forms
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‘
class StarkHandler(object):
def save(self, form, is_update=False):
"""
在使用ModelForm保存数据之前预留的钩子方法
"""
form.save()
model_form_class = None
def get_model_form_class(self):
if self.model_form_class:
# 如果自定义了model_form_class,及用自定义的,如果没有,用默认的
return self.model_form_class
class DynamicModelForm(StarkModelForm): #继承StarkModelForm,来继承bootstrap样式
class Meta:
model = self.model_class # 根据当前的model,来显示
fields = "__all__"
return DynamicModelForm
def reverse_list_url(self):
name = "%s:%s" % (self.site.namespace, self.get_list_url_name,)
base_url = reverse(name)
param = self.request.GET.get(‘_filter‘)
if not param:
return base_url
return "%s?%s" % (base_url, param,)
def add_view(self, request):
"""
添加页面
: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)
# 验证传回的form表单信息
if form.is_valid():
self.save(form, is_update=False)
# 在数据库保存成功后,跳转回列表页面(携带原来的参数)。
return redirect(self.reverse_list_url())
return render(request, ‘stark/change.html‘, {‘form‘: form})
stark.py
class UserInfoModelForm(StarkModelForm):
class Meta:
model = models.UserInfo
fields = [‘name‘, ‘gender‘, ‘classes‘, ‘age‘, ‘email‘]
class UserInfoHandler(StarkHandler):
model_form_class = UserInfoModelForm
# 自定义要渲染的form表单,由于在显示的时候可以
site.register(models.UserInfo,UserInfoHandler)
? 根据pk值,来展示编辑页面,所有要传入pk
? 看到的东西有默认值
class StarkHandler(object):
list_display = []
def display_edit(self, obj=None, is_header=None):
"""
自定义页面显示的列(表头和内容)
"""
if is_header:
return "编辑"
return mark_safe(‘<a href="%s">编辑</a>‘ % self.reverse_change_url(pk=obj.pk))
def reverse_change_url(self, *args, **kwargs):
"""
# 在原基础上, *args, **kwargs
生成带有原搜索条件的编辑URL
:param args:
:param kwargs:
:return:
"""
name = "%s:%s" % (self.site.namespace, self.get_change_url_name,)
base_url = reverse(name, args=args, kwargs=kwargs)
if not self.request.GET:
add_url = base_url
else:
param = self.request.GET.urlencode()
new_query_dict = QueryDict(mutable=True)
new_query_dict[‘_filter‘] = param
add_url = "%s?%s" % (base_url, new_query_dict.urlencode())
return add_url
# 在最开始的时候要获取到pk值
def get_urls(self):
# 正则获取pk值
patterns = [
url(r‘^list/$‘, self.wrapper(self.changelist_view), name=self.get_list_url_name),
url(r‘^add/$‘, self.wrapper(self.add_view), name=self.get_add_url_name),
url(r‘^change/(?P<pk>\d+)/$‘, self.wrapper(self.change_view),
name=self.get_change_url_name),
url(r‘^delete/(?P<pk>\d+)/$‘, self.wrapper(self.delete_view), name=self.get_delete_url_name),
]
patterns.extend(self.extra_urls())
return patterns
def change_view(self, request, pk):
"""
编辑页面
:param request:
:param pk:
:return:
"""
current_change_object = self.model_class.objects.filter(pk=pk).first()
if not current_change_object:
return HttpResponse(‘要修改的数据不存在,请重新选择!‘)
model_form_class = self.get_model_form_class()
if request.method == ‘GET‘:
form = model_form_class(instance=current_change_object)
# 获取当前models的form组件来渲染form表单
return render(request, ‘stark/change.html‘, {‘form‘: form})
form = model_form_class(data=request.POST, instance=current_change_object)
if form.is_valid():
self.save(form, is_update=False)
# 在数据库保存成功后,跳转回列表页面(携带原来的参数)。
return redirect(self.reverse_list_url())
return render(request, ‘stark/change.html‘, {‘form‘: form})
class StarkHandler(object):
def display_del(self, obj=None, is_header=None):
if is_header:
return "删除"
return mark_safe(‘<a href="%s">删除</a>‘ % self.reverse_delete_url(pk=obj.pk))
def reverse_delete_url(self, *args, **kwargs):
"""
生成带有原搜索条件的删除URL
:param args:
:param kwargs:
:return:
"""
name = "%s:%s" % (self.site.namespace, self.get_delete_url_name,)
base_url = reverse(name, args=args, kwargs=kwargs)
if not self.request.GET:
add_url = base_url
else:
param = self.request.GET.urlencode()
new_query_dict = QueryDict(mutable=True)
new_query_dict[‘_filter‘] = param
add_url = "%s?%s" % (base_url, new_query_dict.urlencode())
return add_url
def delete_view(self, request, pk):
"""
删除页面
:param request:
:param pk:
:return:
"""
origin_list_url = self.reverse_list_url()
if request.method == ‘GET‘:
return render(request, ‘stark/delete.html‘, {‘cancel‘: origin_list_url})
self.model_class.objects.filter(pk=pk).delete()
return redirect(origin_list_url)
order_list = []
def get_order_list(self):
return self.order_list or [‘-id‘, ]
def changelist_view(self, request):
"""
列表页面
:param request:
:return:
"""
# ########## 1. 获取排序 ##########
order_list = self.get_order_list()
queryset = self.model_class.objects.all().order_by(*order_list)
# 以下的数据都经过 排序,以下都用queryset
实现思路:
在页面设置form表单,搜索:以get形式提交到后台,后台获取数据然后进行筛选
? 在后端获取关键字后,根据
from django.db.models import Q
search_list = [‘name__contains‘,] # 如果不加__contains就算精确查找
def get_search_list(self):
return self.search_list
def changelist_view(self, request):
"""
列表页面
:param request:
:return:
"""
# ########## 0. 模糊查询 ##########
#1,如果search_list 中没有值,则不显示搜索框
#2.获取用户提交的关键字
# 3.构造条件
# Django Q 对象,用户构造复杂的orm查询条件
search_list = self.get_search_list()
search_value = request.GET.get(‘q‘, ‘‘)
conn = Q()
conn.connector = ‘OR‘
if search_value:
# 如果用户没有搜索,就不构造
for item in search_list:
conn.children.append((item, search_value))
# ########## 1. 获取排序 ##########
order_list = self.get_order_list()
queryset = self.model_class.objects.filter(conn).order_by(*order_list)
# filter.all()变成了filter(conn)
添加checkbox列
生成批量操作的按钮
在display_list中添加一列
将函数传入 html,中,函数会自动执行
将提交的函数名,通过反射来找函数执行
扩展,handler的函数预留参数接口 *args, **kwargs
扩展,点击批量操作的执行后,能够跳转某个页面去查看某些内容
change_listhtml.
{% if action_dict %}
// 如果下拉框有值才显示,
<div style="float: left;margin: 5px 10px 5px 0;">
<div class="form-inline">
<div class="form-group">
<select class="form-control" name="action">
<option value="">请选择操作</option>
{% for func_name,func_text in action_dict.items %}
<option value="{{ func_name }}">{{ func_text }}</option>
{% endfor %}
</select>
<input class="btn btn-primary" type="submit" value="执行"/>
</div>
</div>
</div>
{% endif %}
def display_checkbox(self, obj=None, is_header=None):
"""
:param obj:
:param is_header:
:return:
"""
if is_header:
return "选择"
return mark_safe(‘<input type="checkbox" name="pk" value="%s" />‘ % obj.pk)
action_list = [] #在里面放上函数
def get_action_list(self):
return self.action_list
def action_multi_delete(self, request, *args, **kwargs):
"""
批量删除(如果想要定制执行成功后的返回值,那么就为action函数设置返回值即可。) return redirect(‘html‘)
:return:
"""
pk_list = request.POST.getlist(‘pk‘)
self.model_class.objects.filter(id__in=pk_list).delete()
action_multi_delete.text = "批量删除"
def changelist_view(self, request, *args, **kwargs):
"""
列表页面
:param request:
:return:
"""
# ########## 1. 处理Action ##########
action_list = self.get_action_list()
# 将函数传入 html,中,函数会自动执行,所以将函数改为字典
action_dict = {func.__name__: func.text for func in action_list} # {‘multi_delete‘:‘批量删除‘,‘multi_init‘:‘批量初始化‘}
if request.method == ‘POST‘:
action_func_name = request.POST.get(‘action‘)
if action_func_name and action_func_name in action_dict:
# 用户提交的函数必须是我们定义过的,避免用户修改html代码来破坏
action_response = getattr(self, action_func_name)(request, *args, **kwargs)
if action_response:
# 如果函数有返回值,就证明要跳转到某个页面
return action_response
什么是组合搜索
如何实现组合搜索
实现思路
第一步:根据字段找到其关联的数据,choice,FK,M2M
第二步:根据配置获取关联数据,不写,就不显示
第三步:根据配置获取相关数据(含条件)
第四步:
第五步:为组合
生成url时,不影响其他组影响、
1. 手动拼接,"/stark/app01/userinfo/list" + ‘?depart=1‘
2. 根据request.get来生成,每点击一次,都能生成根据这次点击,而形成的url
query_dict = self.rquests.copy()
query_dict._mutable = True
query_dict[‘depart‘] = 1
?
class SearchGroupRow(object):
def __init__(self, title, queryset_or_tuple, option):
"""
# 将querysert,或元组,组装成一个统一的可迭代对象
:param title: 组合搜索的列名称
:param queryset_or_tuple: 组合搜索关联获取到的数据
:param option: 配置
"""
self.title = title
self.queryset_or_tuple = queryset_or_tuple
self.option = option
def __iter__(self):
yield ‘<div class="whole">‘
yield self.title
yield ‘</div>‘
yield ‘<div class="others">‘
yield "<a>全部</a>"
for item in self.queryset_or_tuple:
text = self.option.get_text(item)
yield "<a href=‘#‘>%s</a>" % text
#此处写死,不易扩展,比如要对字符串进行加工,所以取一个函数返回值
yield ‘</div>‘
class Option(object):
def __init__(self, field, db_condition=None, text_func=None):
"""
:param field: 组合搜索关联的字段
:param db_condition: 数据库关联查询时的条件
:param text_func: 此函数用于显示组合搜索按钮页面文本
"""
self.field = field
if not db_condition:
db_condition = {}
self.db_condition = db_condition
self.text_func = text_func
self.is_choice = False
def get_db_condition(self, request, *args, **kwargs):
return self.db_condition
def get_queryset_or_tuple(self, model_class, request, *args, **kwargs):
"""
根据字段去获取数据库关联的数据
:return:
"""
# 根据gender或depart字符串,去自己对应的Model类中找到 字段对象
field_object = model_class._meta.get_field(self.field)
title = field_object.verbose_name
# 获取关联数据
if isinstance(field_object, ForeignKey) or isinstance(field_object, ManyToManyField):
# FK和M2M,应该去获取其关联表中的数据: QuerySet
db_condition = self.get_db_condition(request, *args, **kwargs)
return SearchGroupRow(title, field_object.rel.model.objects.filter(**db_condition), self)
else:
# 获取choice中的数据:元组
self.is_choice = True
return SearchGroupRow(title, field_object.choices, self)
def get_text(self, field_object):
"""
获取文本函数,
:param field_object:
:return:
"""
if self.text_func:
return self.text_func(field_object)
if self.is_choice:
return field_object[1]
return str(field_object)
class StarkHandler(object):
search_group = []
def get_search_group(self):
return self.search_group
def changelist_view(self, request, *args, **kwargs):
"""
列表页面
:param request:
:return:
"""
search_group_row_list = []
search_group = self.get_search_group()
# [‘gender‘, ‘depart‘]
for option_object in search_group:
# 根据gender或depart 字符串,去自己对应的model类中找到字段对象
option_object.get_queryset_or_tuple(self.model_class, request, *args, **kwargs)
search_group_row_list.append(row)
stark.py
class UserInfoHandler(StarkHandler):
search_group = [
Option(‘gender‘),
MyOption(‘depart‘, {‘id__gt‘: 2}),
]
site.register(models.UserInfo, UserInfoHandler)
总结:
列表页面
添加页面
编辑页面
删除页面
关键字搜索
批量操作
组合搜索
保留原函数的信息
后台make_safe,和前端管道符safe效果一样
标签:单例模式 cond end 功能实现 ppc xxxx 渲染 serve get
原文地址:https://www.cnblogs.com/leiyiming/p/12807872.html