stark组件
stark组件是根据Django admin为原型写的一个组件,能够让我们告别增删改查.stark组件是可插拔试的组件,
移植性强,而且只用配置文件就能够得到想要的数据
一、stark组件路由分发
admin用这一条路由就实现了注册表单*4的url。
路由分发的原理:
知识一:admin之路由分发原理: def text01(request): return HttpResponse('text01') def text02(request): return HttpResponse('text02') def text03(request): return HttpResponse('text03') urlpatterns = [ path('chen/',( [path('text01/',text01), path('text02/',text02), path('text03/',text03), ], None,None)) ] 由一个路由分发出来三个 第一个none是namespace,第二个是项目名称 一级: path('chen/',( [ path() path() path() ],None,None)) 由一个路由分发出来三个,第一个路由又可以分发出来两个,二级路由. 第一个none是namespace,第二个是项目名称 二级: path('chen/',( [ path( [ path(), path(), ],None,None)) ] ,None,None))
单例模式:
***公共的数据***
一个类只允许实例一个对象
***为了数据统一****
怎么生成单例模式?
方式一:__new__
__new__ class Singleton(object): _instance = None def __new__(cls, *args, **kwargs): # 第一次生成对象的时候走: if not cls._instance: cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) # 第二次走的时候直接走这里 return cls._instance class MyClass(Singleton): a = 1 #那么每次实例对象的时候都是指向 同一个内存地址. #实例MyClass的时候都是 同一个对象
方式二:python模块
python模块是天然的单例模式:
1.不管模块哪里导入,只要是再次导入都是从.pyc导入,都是一个内存地址
因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,
就会直接加载 .pyc 文件,而不会再次执行模块代码。
2.我们只需把模块的对象实例化,每次调用的时候都调用这个对象,就可以获得一个单例对象了。
class StarkSite(object): """注册model对应的配置类(MondelStark或用户自定制)""" def __init__(self): self._registry={} #self--->site单例对象 def register(self,model,stark_class=None): if not stark_class: stark_class=MondelStark self._registry[model] = stark_class(model,self) def get_urls(self): # self--->site单例对象 temp=[] for model,stark_class_obj in self._registry.items(): model_name=model._meta.model_name app_label =model._meta.app_label temp.append(path('%s/%s/'%(app_label,model_name),stark_class_obj.get_url_dispath)) ''' path('repository/book/'BookStark(book,).get_url_dispath) path('repository/author/'BookStark(author,).get_url_dispath) ''' return temp @property def urls(self): return self.get_urls(),None,None site=StarkSite()
每次调用site就是单例对象
说完单例模式,再说回路由的分发:
stark.site就是一个单例,里面进行注册我们的models
为什么我们要用单例模式???
为了能够把model注册到同一个对象里面,我们就可以实现数据统一调度。
StarkSite形成单例类的代码:
#单例的类 class StarkSite(object): """注册model对应的配置类(MondelStark或用户自定制)""" def __init__(self): self._registry={} #self--->site单例对象 def register(self,model,stark_class=None): if not stark_class: stark_class=MondelStark self._registry[model] = stark_class(model,self) def get_urls(self): # self--->site单例对象 temp=[] for model,stark_class_obj in self._registry.items(): model_name=model._meta.model_name app_label =model._meta.app_label temp.append(path('%s/%s/'%(app_label,model_name),stark_class_obj.get_url_dispath)) ''' path('repository/book/'BookStark(book,).get_url_dispath) path('repository/author/'BookStark(author,).get_url_dispath) ''' return temp @property def urls(self): return self.get_urls(),None,None
在register()方法里面,我们在注册的前提
大前提!!!!!!!
***思考***
我们里在直接调用这个register方法?
那么里面注册了数据了吗?
答案是没有的,
***思路***
在每次开启项目的时候,能够自动执行某个py文件进行注册
from repository import models from stark.server.stark import site from stark.server.stark import MondelStark
#我们需要在stark项目的app里: from django.apps import AppConfig from django.utils.module_loading import autodiscover_modules class StarkConfig(AppConfig): name = 'stark' def ready(self): autodiscover_modules('stark',) #每次启动都会执行每个项目的stark.py文件,那么一开启项目就把model注册了. ###########其他项目注册model########## site.register(models.Book,BookStark) site.register(models.Author,AuthorStark) site.register(models.publish)
在其他项目stark.py我们可以自己进行配置类的书写
from stark.server.stark import MondelStark class BookStark(MondelStark): pass
如何通过模型类获得字符串名称,和该模型所在的app名称:
我们需要构建的是一级分发:
第一个是model所属项目的名称/第二个是model类的类名
(path('%s/%s'%(app_label,model_name),))
for model,class_obj in admin.site._registry.items(): print(model._meta.model_name) #打印出该模型的名称 print(model._meta.app_label) #打印出该模型的app的名称
二级分发我们需要写在配置类里面:
为什么不能写在单例?
从图中可以看出,如果是单例对象的话,每个model类对应的视图函数都是一样的
我们想要的是每一个model类都需要4个视图函数,
所以我们只能把二级分发放在配置类里面,让每个配置类都生成四个相对应的视图函数
def url_dispath(self): # self--->stark_class_obj--->每一个单独的配置类. temp = [] model_name = self.model._meta.model_name app_label = self.model._meta.app_label temp.extend([path('add/', self.add_view,name="%s_%s_add"%(app_label,model_name)), re_path('^(d+)/delete/', self.delete_view,name="%s_%s_delete"%(app_label,model_name)), re_path('^(d+)/change/', self.change_view,name="%s_%s_change"%(app_label,model_name)), path('', self.show_list,name="%s_%s_list"%(app_label,model_name))]) return temp #起别名,目的是为了反向查询的时候能够查到相对应的url
构建表结构:
自定制表头:
配置类继承了MondelStark的配置类
class BookStark(MondelStark): list_display=['id','name','price'] site.register(models.Book,BookStark)
构建表格
构建表头知识补充:
#如果客户自定制了配置list_display 那么实例化的时候就先在用户自定义的类里面找
#有则返回给后端......没有再去他的父类里面找list_display为空.
属性的反射
属性和方法都可以进行反射
################### 反射: class B(object): def__init__(self,name): self.name=name chen=B('chenxuming') s='name' ret=getattr(chen,s) print(ret) ---->'chenxuming'
如何将表头换成中文:
val = self.config.model._meta.get_field(field).verbose_name
header_list.append(val)
class Book(models.Model): name = models.CharField(max_length=64,verbose_name='书名') price= models.IntegerField() name=Book._meta.get_field('name') #name拿到的是title字段的对象 print(name) print(type(name)) #可以取里面的属性 name.max_length --->64 name.verbose_name--->'书名'
#判断是否是函数的字段
if callable():
from django.utils.safestring import mark_safe
mark_safe(安全调用标签)
构建表格的代码
def new_list_display(self): ''''构建初始化列表的字段'' temp=[] temp.append(MondelStark.checkbox) temp.extend(self.list_display) temp.append(MondelStark.get_delete_msg) if not self.list_display_links: temp.append(MondelStark.get_edit_msg) return temp def get_headers(self): # 构建表头: self.new_list_display=[checkbox,'name','price',delete,edit] header_list = [] for field in self.config.new_list_display: if callable(field): val = field(self.config, header=True) header_list.append(val) else: if field == '__str__': val = self.config.model_name.upper() header_list.append(val) else: val = self.config.model._meta.get_field(field).verbose_name header_list.append(val) return header_list def get_body(self): # 表数据的创建 new_list = [] for obj in self.data_list: item_list = [] for item in self.config.new_list_display: if callable(item): val = item(self.config, obj) else: val = getattr(obj, item) if item in self.config.list_display_links: val = mark_safe('<a href="%s">%s</a>' % ( self.config.get_edit_url(obj), val)) item_list.append(val) new_list.append(item_list) return new_list [[数据],[数据],[数据]] ##########表头,部分表数据的函数######### def checkbox(self,obj=None,header=False): if header: return mark_safe('<input id="choice_all" type="checkbox">') return mark_safe('<input class="item" type="checkbox" name="selected_id" value="%s">'%obj.id) def get_edit_msg(self,obj=None,header=False): if header: return "操作" _url=self.get_edit_url(obj) return mark_safe('<a href="%s">编辑</a>' % _url) def get_delete_msg(self,obj=None,header=False): if header: return "操作" _url=self.get_delete_url(obj) return mark_safe('<a href="%s">删除</a>'%_url)
增:
增和改都是基于ModelForm来实现的。
如果用户自定制
Stark_Model_Form=自定制modelform的类名
class BookStark(MondelStark): list_display=['id','name','price'] Stark_Model_Form=ModelFormBook list_display_links = ['name'] class ModelFormBook(ModelForm): """自定制ModelForm类""" class Meta: model=models.Book fields='__all__' labels={ 'name':'书名', 'price':'价格', 'pub':'出版社', 'author':'作者', } def get_model_class(self): '''判断是否自定制了ModelForm''' if not self.Stark_Model_Form: from django.forms import ModelForm class ModelDeMo(ModelForm): class Meta: model = self.model fields = '__all__' return ModelDeMo else: return self.Stark_Model_Form def add_view(self,request): '''增加的视图函数''' # self--->stark_class_obj--->每一个单独的配置类. ModelDeMo=self.get_model_class() if request.method=='GET': form =ModelDeMo() return render(request, 'oprate/add.html', {'form':form}) if request.method=='POST': form = ModelDeMo(request.POST) if form.is_valid(): form.save() return redirect(self.get_list_url()) else: return render(request,'oprate/add.html',{'form':form}) ###########前端######### <form class="form-horizontal col-sm-7" method="post" novalidate> {% csrf_token %} {% for data in form %} <label>{{ data.label }}</label> {{ data }} <div class="errors-form">{{ data.errors.0 }}</div> {% endfor %} <button type="submit" class="btn btn-success">提交</button> </form>
改:
和增加差不多
def change_view(self,request,nid): '''改 视图函数''' # self--->stark_class_obj--->每一个单独的配置类. ModelDeMo=self.get_model_class() change_obj=self.model.objects.filter(id=nid).first() if request.method=='GET': form=ModelDeMo(instance=change_obj) return render(request,'oprate/edit.html',{'form':form}) if request.method=='POST': show_url = self.get_list_url() #instance=change_obj # form.save() #执行的是update操作 form=ModelDeMo(data=request.POST,instance=change_obj) if form.is_valid(): form.save() return redirect(show_url) else: return render(request, 'oprate/edit.html', {'form': form}) ###前端### <form class="form-horizontal col-sm-7" method="post" novalidate> {% csrf_token %} {% for data in form %} <label>{{ data.label }}</label> {{ data }} <div class="errors-form">{{ data.errors.0 }}</div> {% endfor %} <button type="submit" class="btn btn-success">提交</button> </form>
删:
删要注意的是需要跳转到一个页面,确保用户误点
def delete_view(self,request,nid): # 删除视图函数 # self--->stark_class_obj--->每一个单独的配置类. del_obj = self.model.objects.filter(id=nid).first() show_url = self.get_list_url() if request.method=='GET': return render(request,'oprate/delete.html',{'show_url':show_url}) if request.method=='POST': if del_obj: del_obj.delete() return redirect(show_url) ###前端###### <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>删除页面</h1> <form action="" method="post" novalidate> {% csrf_token %} <input type="submit" value="确认删除"> <a href="{{ show_url }}">取消</a> </form> </body> </html>
search
用户能够自己配置进行模糊查询
Q方法的补充
from django.db.models import Q Q的两种玩法: 第一种: 查询字段必须是字段 Book.objects.filter(Q(title='yuan')|Q(price=123)) 第二种 查询字段可以是字符串: #实例化一个Q对象 search_connction=Q() #或查询默认是and search_connction.connector='or' for search_fiile in self.search_fiile #self.search_fiile 用户自定制的['name','price'] #append里面是一个元组 #search_connction.children.append((search_fiile,'查询的内容')) search_connction.children.append((search_fiile+'__contains','查询的内容'))模糊查询 data_list = self.model.objects.filter(search_list)
stark实现search
需要自定制字段:
search_fields = ['name']
def get_search_connection(self,request): '''获取模糊查询的Q''' self.key_word=request.GET.get('q','') search_connction=Q() if self.key_word: search_connction.connector='or' for fields in self.search_fields: search_connction.children.append((fields+'__icontains',self.key_word)) return search_connction search_list=self.get_search_connection(request) data_list = self.model.objects.filter(search_list) ##前端## {% if showlist.config.search_fields %} <form action="" method="get" class="pull-right"> <input type="text" name="q" value="{{ showlist.config.key_word }}"><button>查询</button> </form> {% endif %}