crm项目-stark组件
############### admin基本认识和常用的定制功能 ###############
- stark组件
- 对admin的基本认识
- 1,就是一个app,嵌入到了django里面,你可以在settings中看到
- 2,就是一个web后台管理工具,使用它可以更加的方便
- 3,通常我们在生成项目时会在 urls.py 中自动设置好url访问路径
- urlpatterns = [
- url(r'^admin/', admin.site.urls)
- ]
- 4,启动开发服务器,然后在浏览器中访问 http://127.0.0.1:8000/admin/
- 5,你通过命令 python manage.py createsuperuser 来创建超级用户
- 6,使用的时候先注册数据模型:admin.site.register(models.UserInfo)
- 7,点击进入会展示数据,默认就是把这个对象打印出来,复杂的,需要定制的,需要利用ModelAdmin进行操作
- class CourseConfig(admin.ModelAdmin):
- pass
- admin.site.register(Course,CourseConfig)
- #######################
- class UserInfoConfig(admin.ModelAdmin):
- list_display=["id","name","username","password","email","depart"] # 定制显示的列。不能放多对多的字段
- list_display_links=["username"] # 定制列可以点击跳转到详情页面,
- list_filter=["depart"] # 定制右侧快速筛选。
- list_editable=["email"] # 可以编辑的列,可以编辑就不能是list_display_links字段了,
- search_fields=["username"] # 模糊搜索的功能
- # 定义action的函数
- def func(self,request,queryset):
- print(request,queryset)
- queryset.update(email="1212@qq.com")
- func.short_description = "批量初始化操作"
- actions=[func,] # 定制action中的操作
- fields=["username"] # 查看详情和新增页面,可以控制显示的字段
- ordering=["-id"] # 数据排序规则,倒序在字段前面加符号,
- admin.site.register(UserInfo,UserInfoConfig)
############### admin的url设计的基础知识点 ###############
- admin的url是怎么设计的,这是核心,
- urlpatterns = [
- url(r'^admin/', admin.site.urls), # 为什么这一句能能够生成多条url,
- ]
第一个知识点,url的嵌套使用
- def yuan(request):
- return HttpResponse("Yuan")
- def test01(request):
- return HttpResponse("test01")
- def test02(request):
- return HttpResponse("test02")
- def test03(request):
- return HttpResponse("test03")
- def test04(request):
- return HttpResponse("test04")
- def test05(request):
- return HttpResponse("test05")
- urlpatterns = [
- url(r'^admin/', admin.site.urls),
- url(r'^yuan/', ([
- url(r'^test01/', ([
- url(r'^test04/', test04), # http://127.0.0.1:8000/yuan/test01/test04/
- url(r'^test05/', test05),
- ], None, None)),
- url(r'^test02/', test02),
- url(r'^test03/', test03),
- ], None, None))
- ]
第二个知识点:单例模式,
- # 单例模式
- # 一个类只允许实例一个对象
- # class Singleton(object):
- # _instance = None
- # def __new__(cls, *args, **kw):
- # if not cls._instance:
- # cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)
- # return cls._instance
- #
- # class MyClass(Singleton):
- # a = 1
- #
- #
- # one = MyClass()
- # one.a=3
- #
- # two = MyClass()
- # print(two.a) # 这个地方就是3,因为one和two指向的同一个内存空间,one改掉了a=3,所以two取值的时候就是3
- #
- # # print(one==two)
- # # print(id(one),id(two))
- # 第二种方法
- ###########################
- # 第一个文件
- class My_Singleton(object):
- x =12
- def foo(self):
- print(self.x)
- my_singleton = My_Singleton() # 这是一个关键的一步
- print("OK")
- ###################
- # 第二个文件
- from mysingleton import my_singleton
- def foo():
- print(id(my_singleton))
- ############
- # 第三个文件
- from mysingleton import my_singleton,My_Singleton
- # a=My_Singleton()
- # b=My_Singleton()
- #
- # print(id(a))
- # print(id(b)) # 这是拿的类对象,而不是实例对象,所以,这两个不一样,
- print(id(my_singleton))
- from mysingleton import my_singleton
- print(id(my_singleton))
- from func import *
- foo() # 这三次都是拿的实例对象,所以id的结果都是一样的,
############### admin的url设计 ###############
第一个注册:
- # 注册
- self._registry = {}
- self._registry[model] = admin_class(model, self)
- # 注册的时候,是定义了一个字典,然后以model表为键,以对应的自定义类为值,生成对应的字典,
第二个url设置
- def add(request):
- return HttpResponse("add")
- def delete(request,id):
- return HttpResponse("delete")
- def change(request,id):
- return HttpResponse("change")
- def list_view(request):
- return HttpResponse("list_view")
- def get_urls2():
- temp=[]
- temp.append(url(r"^add/",add))
- temp.append(url(r"^(\d+)/delete/",delete))
- temp.append(url(r"^(\d+)/change/",change))
- temp.append(url(r"^$",list_view))
- print("temp2",temp)
- # [
- # <RegexURLPattern None ^add/>,
- # <RegexURLPattern None ^(\d+)/delete/>,
- # <RegexURLPattern None ^(\d+)/change/>,
- # <RegexURLPattern None ^$>
- # ]
- return temp
- def get_urls():
- temp=[]
- print("_registry",admin.site._registry)
- for model,admin_class_obj in admin.site._registry.items():
- print("model",model) # 所有的注册模型表
- # < class 'app01.models.Book'>-----> "book" "app01"
- # < class 'app01.models.Room'>-----> "room" "app01"
- print("===>",model._meta.model_name)
- print("===>",model._meta.app_label)
- model_name=model._meta.model_name # 对应的model表的名字
- app_label=model._meta.app_label # 对应的app名字
- temp.append(url(r"%s/%s/"%(app_label,model_name),(get_urls2(),None,None)))
- print("temp",temp)
- """
- [
- <RegexURLResolver <RegexURLPattern list> (None:None) auth/group/>,
- <RegexURLResolver <RegexURLPattern list> (None:None) auth/user/>,
- <RegexURLResolver <RegexURLPattern list> (None:None) crm/userinfo/>
- ]
- """
- return temp
- urlpatterns = [
- url(r'^admin/', admin.site.urls),
- url(r'^yuan/', (get_urls(), None, None))
- ]
############### 模仿admin-stark组件的url设计 ###############
- class ModelStark(object):
- def __init__(self,model,site):
- self.model=model # 谁调用的就是那个表
- self.site=site
- def add_view(self, request):
- return HttpResponse("add_view")
- def change_view(self, request, id):
- return HttpResponse("change_view")
- def delete_view(self, request, id):
- return HttpResponse("delete_view")
- def list_view(self, request):
- return HttpResponse("list_view")
- def get_urls_2(self):
- temp = []
- model_name=self.model._meta.model_name
- app_label=self.model._meta.app_label
- temp.append(url(r"^add/", self.add_view))
- temp.append(url(r"^(\d+)/delete/", self.delete_view))
- temp.append(url(r"^(\d+)/change/", self.change_view))
- temp.append(url(r"^$", self.list_view))
- return temp
- @property
- def urls_2(self):
- print(self.model)
- return self.get_urls_2(), None, None
- class StarkSite(object):
- def __init__(self):
- self._registry={}
- def register(self,model,stark_class=None):
- if not stark_class:
- stark_class=ModelStark
- self._registry[model] = stark_class(model, self) # 括号内的两个参数,就是ModelStark默认的两个参数,self就是site
- def get_urls(self):
- temp=[]
- for model,stark_class_obj in self._registry.items():
- model_name=model._meta.model_name
- app_label=model._meta.app_label
- # 分发增删改查
- temp.append(url(r"^%s/%s/"%(app_label,model_name),stark_class_obj.urls_2))
- '''
- url(r"^app01/userinfo/",UserConfig(Userinfo).urls_2),
- url(r"^app01/book/",ModelStark(Book).urls_2),
- '''
- return temp
- @property
- def urls(self):
- return self.get_urls(),None,None
- site=StarkSite() # 单例模式
############## stark组件需要实现的功能 ###############
- 在完成了注册和url设计之后,stark组件需要完成什么功能
- 1,查询页面
- 1.1 表头展示,可以定制展示的列,
- 1.2 表内容展示,删除 编辑,复选框的功能
- 1.3 查询功能,可以定义查询的字段,
- 1.4 action功能,可以定制批量操作
- 1.5 筛选功能,可以定制筛选的字段,
- 1.6 分页功能
- 这是最为复杂的部分,
- 2,新增页面
- 2.1 一个重要的pop功能,
- 3,删除页面
- 这个简单
- 4,编辑页面,
- 这个简单,和新增页面很相似,只需要把要编辑的数据带到页面展示,
- 整个重写,使用到了
- 1,django
- 2,admin
- 3,前端,js,html,bootstrap,jQuery,
############## stark-service ###############
- # by luffycity.com
- from django.conf.urls import url
- from django.shortcuts import HttpResponse,render,redirect
- from django.urls import reverse
- from django.db.models import Q
- from django.utils.safestring import mark_safe
- from stark.utils.page import Pagination
- from django.db.models.fields.related import ManyToManyField,ForeignKey
- class ShowList(object):
- def __init__(self,config,data_list,request):
- self.config=config # 这里的config就是用来接收传递的modelstark类的,下面就可以使用config调用modelstark里面的方法了,
- self.data_list=data_list # 这个datalist是需要展示的数据
- self.request=request # 为什么需要传递request?因为需要在这个里面获取page参数,是第几页
- #分页
- data_count=self.data_list.count()
- current_page=int(self.request.GET.get("page",1))
- base_path=self.request.path
- self.pagination=Pagination(current_page,data_count,base_path,self.request.GET,per_page_num=10, pager_count=11, )
- self.page_data=self.data_list[self.pagination.start:self.pagination.end]
- # actions
- self.actions=self.config.new_actions() # [patch_init,] # 获取modelstark中配置的action列表,
- def get_filter_linktags(self):
- print("list_filter:",self.config.list_filter)
- link_dic={} # 格式是{筛选字段1:筛选值1,筛选字段2:筛选值2}
- import copy
- for filter_field in self.config.list_filter: # ["title","publish","authors",]
- params = copy.deepcopy(self.request.GET) # 复制一份方便操作
- cid=self.request.GET.get(filter_field,0) # 这是获取到前端拼接的id,
- print("filter_field",filter_field) # "publish"
- filter_field_obj=self.config.model._meta.get_field(filter_field) # 这是拿到的字段对象
- print("filter_field_obj",filter_field_obj)
- print(type(filter_field_obj))
- from django.db.models.fields.related import ForeignKey
- from django.db.models.fields.related import ManyToManyField
- # 举例说明:拿到出版社关联的书籍,筛选是所有关联的出版社,拿到作者关联的书籍,筛选是所有关联的作者,怎么获取?
- print("rel======...",filter_field_obj.rel)
- if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):
- data_list=filter_field_obj.rel.to.objects.all()# 【publish1,publish2...】
- # filter_field_obj.rel.to,这种特殊写法,只有字段有关联表的时候才有意义,一对多,和多对多的,
- else:
- data_list=self.config.model.objects.all().values("pk",filter_field)
- print("data_list",data_list)
- temp=[]
- # 处理全部标签
- if params.get(filter_field): # filter_field 这是筛选的字段,如果有筛选值,就删掉,
- del params[filter_field]
- temp.append("<a href='?%s'>全部</a>"%params.urlencode())
- else:
- temp.append("<a class='active' href='#'>全部</a>")
- # 处理数据标签
- for obj in data_list:
- if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):
- pk=obj.pk
- text=str(obj)
- params[filter_field] = pk
- else: # data_list= [{"pk":1,"title":"go"},....]
- print("========")
- pk=obj.get("pk")
- text=obj.get(filter_field)
- params[filter_field] =text # 处理单表查询
- _url=params.urlencode()
- if cid==str(pk) or cid==text: # 这是为了实现点击选中的标签,展示深蓝色,active
- link_tag="<a class='active' href='?%s'>%s</a>"%(_url,text)
- else:
- link_tag = "<a href='?%s'>%s</a>" % (_url, text)
- temp.append(link_tag)
- link_dic[filter_field]=temp
- return link_dic
- def get_action_list(self): # 拿到action操作,放到页面去渲染
- temp=[]
- for action in self.actions: # 这是配置的action列表,循环这个列表,每一个action就是每一个函数,
- temp.append({
- "name":action.__name__, # 获取函数的名字,作为值
- "desc":action.short_description # 获取函数的描述,作为展示short_description,这是函数的一个动态属性
- }) # [{"name":""patch_init,"desc":"批量初始化"}]
- print("temp",temp)
- return temp
- def get_header(self):
- # 构建表头
- header_list = []
- print("header",
- self.config.new_list_play()) # [checkbox,"pk","name","age",edit ,deletes] 【checkbox ,"__str__", edit ,deletes】
- for field in self.config.new_list_play():
- if callable(field):
- # header_list.append(field.__name__) # field.__name__函数的名字
- val = field(self.config, header=True) # header=True,header默认是false,这个再去拿值的之后就会拿到汉字了
- header_list.append(val)
- else:
- if field == "__str__": # 这是没有自定义的情况
- header_list.append(self.config.model._meta.model_name.upper()) # 这是展示表名的大写作为表头
- else: # 这是自定义的情况
- # header_list.append(field)
- val = self.config.model._meta.get_field(field).verbose_name # 这是获取到了表里面的字段,verbose_name这是字段的中文
- header_list.append(val)
- return header_list
- def get_body(self):
- # 构建表单数据
- new_data_list = []
- for obj in self.page_data:
- temp = []
- for filed in self.config.new_list_play(): # ["__str__",] ["pk","name","age",edit] 这一步应该把编辑,删除,复选框都加进来了
- if callable(filed): # callable判断是否是一个可调用的,如果是一个字符串就是False,如果是一个方法就是true
- print("obj-----:",obj)
- val = filed(self.config, obj)
- else:
- try:
- field_obj=self.config.model._meta.get_field(filed)
- if isinstance(field_obj,ManyToManyField): # 多对多的时候如何展示数据
- ret = getattr(obj,filed).all() # 这是获取到多对多的情况,可能会有多个值,
- t=[]
- for mobj in ret:
- t.append(str(mobj))
- val=",".join(t) # 拼成逗号隔开的样子,展示出来,
- else:
- print("====>",field_obj.choices)
- if field_obj.choices:
- val = getattr(obj, "get_"+filed+"_display") # 这个obj是每一条数据,filed是每一条数据应该显示的字段,
- else:
- val = getattr(obj, filed)
- if filed in self.config.list_display_links: # 如果是一个可以点击的字段,要特殊处理成为超链接
- # "app01/userinfo/(\d+)/change"
- _url = self.config.get_change_url(obj)
- val = mark_safe("<a href='%s'>%s</a>" % (_url, val))
- except Exception as e:
- val = getattr(obj, filed)
- temp.append(val)
- new_data_list.append(temp)
- return new_data_list
- '''
- [
- [1,"alex",12],
- [1,"alex",12],
- [1,"alex",12],
- [1,"alex",12],
- ]
- '''
- class ModelStark(object):
- list_display=["__str__",]
- list_display_links=[]
- modelform_class=None
- search_fields=[]
- actions = []
- list_filter=[]
- def patch_delete(self, request, queryset):
- """批量删除"""
- queryset.delete()
- patch_delete.short_description = "批量删除"
- def __init__(self,model,site):
- self.model=model
- self.site=site
- # 删除 编辑,复选框
- def edit(self,obj=None,header=False):
- if header:
- return "操作"
- #return mark_safe("<a href='%s/change'>编辑</a>"%obj.pk)
- _url=self.get_change_url(obj)
- return mark_safe("<a href='%s'>编辑</a>"%_url)
- def deletes(self,obj=None,header=False):
- if header:
- return "操作"
- # return mark_safe("<a href='%s/change'>编辑</a>"%obj.pk)
- _url=self.get_delete_url(obj)
- return mark_safe("<a href='%s'>删除</a>" % _url)
- def checkbox(self,obj=None,header=False):
- if header:
- return mark_safe('<input id="choice" type="checkbox">')
- return mark_safe('<input class="choice_item" type="checkbox" name="selected_pk" value="%s">'%obj.pk)
- # 这一步非常的重要,因为在配合action去取到选中的数据,
- def get_modelform_class(self):
- """如果客户定制了用客户定制的,如果没有没有定制使用默认的,"""
- if not self.modelform_class:
- from django.forms import ModelForm # 这个涉及到了form表单的内容,
- from django.forms import widgets as wid
- class ModelFormDemo(ModelForm): # 可以在每一个app中的stark里面,对每一个model进行重写这个类,就可以定制了
- class Meta:
- model = self.model
- fields = "__all__"
- labels={
- ""
- } # 可以在每一个app中的stark里面,labels可以对字段进行设置汉字,格式是键:值的方式,
- return ModelFormDemo
- else:
- return self.modelform_class
- def get_new_form(self,form):
- """这是pop弹出的窗口对象的方法,"""
- for bfield in form:
- from django.forms.boundfield import BoundField
- print(bfield.field) # 字段对象
- print("name",bfield.name) # 字段名(字符串)
- print(type(bfield.field)) # 字段类型
- from django.forms.models import ModelChoiceField
- if isinstance(bfield.field,ModelChoiceField):
- bfield.is_pop=True # 这是动态给多对多的字段加属性
- # 怎么拿到关联表的名字,和它所属的APP呢,
- print("=======>",bfield.field.queryset.model) # 一对多或者多对多字段的关联模型表
- related_model_name=bfield.field.queryset.model._meta.model_name
- related_app_label=bfield.field.queryset.model._meta.app_label
- _url=reverse("%s_%s_add"%(related_app_label,related_model_name)) # 反向解析进入对应的添加页面,
- bfield.url=_url+"?pop_res_id=id_%s"%bfield.name # 动态加字段,字段名(字符串)
- return form
- def add_view(self, request):
- ModelFormDemo = self.get_modelform_class() # 这是返回一个类
- form = ModelFormDemo() # 使用这个类实例化一个对象出来,
- form=self.get_new_form(form)
- if request.method=="POST": # 点击提交按钮要做的事情
- form = ModelFormDemo(request.POST)
- if form.is_valid():
- obj=form.save() # 这都是form表单的功能,校验通过就保存到数据库,
- pop_res_id=request.GET.get("pop_res_id")
- if pop_res_id:
- res ={"pk":obj.pk,"text":str(obj),"pop_res_id":pop_res_id}
- import json
- return render(request, "pop.html", {"res":res})
- else:
- return redirect(self.get_list_url())
- print("locals()",locals())
- """
- {
- 'form': <ModelFormDemo bound=False, valid=Unknown, fields=(qq;name;gender;education;graduation_school;major;experience;work_status;company;salary;source;referral_from;course;status;consultant;recv_date;last_consult_date)>,
- 'ModelFormDemo': <class 'stark.service.stark.ModelStark.get_modelform_class.<locals>.ModelFormDemo'>,
- 'request': <WSGIRequest: GET '/stark/crm/customer/add/'>,
- 'self': <crm.stark.CusotmerConfig object at 0x000000000D1FBC18>
- }
- """
- return render(request, "add_view.html", locals()) # Python 的内建函数 locals() 。它返回的字典对所有局部变量的名称与值进行映射。
- def delete_view(self, request, id):
- url = self.get_list_url()
- if request.method=="POST":
- self.model.objects.filter(pk=id).delete()
- return redirect(url)
- return render(request, "delete_view.html", locals())
- def change_view(self, request, id):
- ModelFormDemo = self.get_modelform_class() # 获取这个类,可以控制展示的字段等信息
- print("=====id",id)
- edit_obj = self.model.objects.filter(pk=id).first()
- if request.method=="POST":
- form = ModelFormDemo(request.POST,instance=edit_obj) # 这个instance也是djangoform表单的功能,
- if form.is_valid():
- form.save()
- return redirect(self.get_list_url()) # 提交之后返回到列表页
- print("locals()",locals())
- return render(request, "change_view.html", locals())
- print("***********",edit_obj)
- form = ModelFormDemo(instance=edit_obj) # 和新增页面一样,只需要加一个instance
- form = self.get_new_form(form)
- return render(request, "change_view.html", locals())
- def new_list_play(self):
- """这个方法不只是把每一条数据的字段放进来了,还把编辑,删除,复选框也放进来了,"""
- temp=[]
- temp.append(ModelStark.checkbox) # 复选框加入
- temp.extend(self.list_display) # 自定义字段加入,这个地方还可以自己自定义函数,传进来,
- if not self.list_display_links: # 如果已经有点击链接可以编辑的入口了,就不需要编辑这一栏了,
- temp.append(ModelStark.edit) # 编辑加入
- temp.append(ModelStark.deletes) # 删除加入
- return temp
- def new_actions(self):
- temp=[]
- temp.append(ModelStark.patch_delete)
- temp.extend(self.actions) # 这个里面就可能会有自定义的action,这样组成一个新的action,
- return temp
- def get_change_url(self,obj): # 这一个功能多个地方使用,所以封装到一个方法里面,
- model_name = self.model._meta.model_name
- app_label = self.model._meta.app_label
- print("obj===========",obj)
- # from django.urls import reverse,这个是django中的一个工具
- _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) # 反向解析,args,是传入的id字段,
- return _url
- def get_delete_url(self, obj):
- model_name = self.model._meta.model_name
- app_label = self.model._meta.app_label
- _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.pk,))
- return _url
- def get_add_url(self):
- model_name = self.model._meta.model_name
- app_label = self.model._meta.app_label
- _url = reverse("%s_%s_add" % (app_label, model_name))
- return _url
- def get_list_url(self):
- model_name = self.model._meta.model_name
- app_label = self.model._meta.app_label
- _url = reverse("%s_%s_list" % (app_label, model_name))
- return _url
- def get_serach_conditon(self,request):
- key_word = request.GET.get("q","")
- self.key_word=key_word # 这是给modelstark加一个实例对象,然后在查询之后就可以直接把查询内容渲染到页面了,通过showlist.config.keyword
- search_connection = Q() # 默认这个是空的条件
- if key_word:
- # self.search_fields # ["title","price"]
- search_connection.connector = "or" # 这是orm使用q查询的另外一种方法,
- for search_field in self.search_fields:
- search_connection.children.append((search_field + "__contains", key_word))
- print("search_connection",search_connection)
- return search_connection
- def get_filter_condition(self,request):
- filter_condition=Q()
- for filter_field,val in request.GET.items():# courserecord=2
- if filter_field !="page": # 把page这个去掉,不加入过滤
- filter_condition.children.append((filter_field,val))
- return filter_condition
- def list_view(self, request):
- if request.method=="POST": # 这个post请求,就是在处理action的提交(go)
- print("POST:",request.POST) # 把input框的值传过来了,把select下面的选中的值传过来,可以在post中取到action和selected_pk
- action=request.POST.get("action") # patch_init
- selected_pk=request.POST.getlist("selected_pk")
- action_func=getattr(self,action) # 反射,从self中去找action,action这是一个变量,是对应的点击的哪一个函数
- # self,是配置类,如果没有找到就去父类找,
- queryset=self.model.objects.filter(pk__in=selected_pk)
- ret=action_func(request,queryset) # 调用对应的函数操作,
- #return ret
- # 获取serach的Q对象
- search_connection=self.get_serach_conditon(request)
- # 获取filter构建Q对象
- filter_condition=self.get_filter_condition(request)
- print("search_connection",search_connection,"filter_condition",filter_condition)
- # 筛选获取当前表所有数据
- data_list=self.model.objects.all().filter(search_connection).filter(filter_condition) # 【obj1,obj2,....】
- print("data_list",data_list)
- # 按这ShowList展示页面
- showlist=ShowList(self,data_list,request) # 实例化一个showlist,这个self就是现在的modelstark类,需要作为一个参数传递,
- # 构建一个查看URL
- add_url=self.get_add_url()
- return render(request, "list_view.html", locals())
- def extra_url(self):
- return []
- def get_urls_2(self):
- temp = []
- model_name=self.model._meta.model_name
- app_label=self.model._meta.app_label
- temp.append(url(r"^add/", self.add_view,name="%s_%s_add"%(app_label,model_name))) # 这个name用来反向解析用
- temp.append(url(r"^(\d+)/delete/", self.delete_view,name="%s_%s_delete"%(app_label,model_name)))
- temp.append(url(r"^(\d+)/change/", self.change_view,name="%s_%s_change"%(app_label,model_name)))
- temp.append(url(r"^$", self.list_view,name="%s_%s_list"%(app_label,model_name)))
- # 扩展url
- temp.extend(self.extra_url())
- return temp
- @property
- def urls_2(self):
- print(self.model)
- return self.get_urls_2(), None, None
- class StarkSite(object):
- def __init__(self):
- self._registry={}
- def register(self,model,stark_class=None):
- if not stark_class:
- stark_class=ModelStark
- self._registry[model] = stark_class(model, self) # 括号内的两个参数,就是ModelStark默认的两个参数,self就是site
- def get_urls(self):
- temp=[]
- for model,stark_class_obj in self._registry.items():
- model_name=model._meta.model_name
- app_label=model._meta.app_label
- # 分发增删改查
- temp.append(url(r"^%s/%s/"%(app_label,model_name),stark_class_obj.urls_2))
- '''
- url(r"^app01/userinfo/",UserConfig(Userinfo).urls_2),
- url(r"^app01/book/",ModelStark(Book).urls_2),
- '''
- return temp
- @property
- def urls(self):
- return self.get_urls(),None,None
- site=StarkSite()
############### stark-分页 ###############
- """
- 自定义分页组件
- """
- class Pagination(object):
- def __init__(self, current_page, all_count, base_url,params, per_page_num=8, pager_count=11, ):
- """
- 封装分页相关数据
- :param current_page: 当前页
- :param all_count: 数据库中的数据总条数
- :param per_page_num: 每页显示的数据条数
- :param base_url: 分页中显示的URL前缀
- :param pager_count: 最多显示的页码个数
- """
- try:
- current_page = int(current_page)
- except Exception as e:
- current_page = 1
- if current_page < 1:
- current_page = 1
- self.current_page = current_page
- self.all_count = all_count
- self.per_page_num = per_page_num
- self.base_url = base_url
- # 总页码
- all_pager, tmp = divmod(all_count, per_page_num)
- if tmp:
- all_pager += 1
- self.all_pager = all_pager
- self.pager_count = pager_count # 最多显示页码数
- self.pager_count_half = int((pager_count - 1) / 2)
- import copy
- params = copy.deepcopy(params)
- params._mutable = True
- self.params = params # self.params : {"page":77,"title":"python","nid":1}
- @property
- def start(self):
- return (self.current_page - 1) * self.per_page_num
- @property
- def end(self):
- return self.current_page * self.per_page_num
- def page_html(self):
- # 如果总页码 < 11个:
- if self.all_pager <= self.pager_count:
- pager_start = 1
- pager_end = self.all_pager + 1
- # 总页码 > 11
- else:
- # 当前页如果<=页面上最多显示(11-1)/2个页码
- if self.current_page <= self.pager_count_half:
- pager_start = 1
- pager_end = self.pager_count + 1
- # 当前页大于5
- else:
- # 页码翻到最后
- if (self.current_page + self.pager_count_half) > self.all_pager:
- pager_start = self.all_pager - self.pager_count + 1
- pager_end = self.all_pager + 1
- else:
- pager_start = self.current_page - self.pager_count_half
- pager_end = self.current_page + self.pager_count_half + 1
- page_html_list = []
- self.params["page"] = 1
- first_page = '<li><a href="%s?%s">首页</a></li>' % (self.base_url, self.params.urlencode(),)
- page_html_list.append(first_page)
- if self.current_page <= 1:
- prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
- else:
- self.params["page"] = self.current_page - 1
- prev_page = '<li><a href="%s?%s">上一页</a></li>' % (self.base_url, self.params.urlencode(),)
- page_html_list.append(prev_page)
- for i in range(pager_start, pager_end):
- # self.params : {"page":77,"title":"python","nid":1}
- self.params["page"] = i # {"page":72,"title":"python","nid":1}
- if i == self.current_page:
- temp = '<li class="active"><a href="%s?%s">%s</a></li>' % (self.base_url, self.params.urlencode(), i,)
- else:
- temp = '<li><a href="%s?%s">%s</a></li>' % (self.base_url, self.params.urlencode(), i,)
- page_html_list.append(temp)
- if self.current_page >= self.all_pager:
- next_page = '<li class="disabled"><a href="#">下一页</a></li>'
- else:
- self.params["page"] = self.current_page + 1
- next_page = '<li><a href="%s?%s">下一页</a></li>' % (self.base_url, self.params.urlencode(),)
- page_html_list.append(next_page)
- self.params["page"] = self.all_pager
- last_page = '<li><a href="%s?%s">尾页</a></li>' % (self.base_url, self.params.urlencode(),)
- page_html_list.append(last_page)
- return ''.join(page_html_list)
- # class Pagination(object):
- #
- # def __init__(self, data_num, current_page, url_prefix,params, per_page=10, max_show=4):
- # """
- # 进行初始化.
- # :param data_num: 数据总数
- # :param current_page: 当前页
- # :param url_prefix: 生成的页码的链接前缀
- # :param per_page: 每页显示多少条数据
- # :param max_show: 页面最多显示多少个页码
- # """
- # self.data_num = data_num
- # self.per_page = per_page
- # self.max_show = max_show
- # self.url_prefix = url_prefix
- #
- # # 把页码数算出来
- # self.page_num, more = divmod(data_num, per_page)
- # if more:
- # self.page_num += 1
- #
- # try:
- # self.current_page = int(current_page)
- # except Exception as e:
- # self.current_page = 1
- # # 如果URL传过来的页码数是负数
- # if self.current_page <= 0:
- # self.current_page = 1
- # # 如果URL传过来的页码数超过了最大页码数
- # elif self.current_page > self.page_num:
- # self.current_page = self.page_num # 默认展示最后一页
- #
- # # 页码数的一半 算出来
- # self.half_show = max_show // 2
- #
- # # 页码最左边显示多少
- # if self.current_page - self.half_show <= 1:
- # self.page_start = 1
- # self.page_end = self.max_show
- # elif self.current_page + self.half_show >= self.page_num: # 如果右边越界
- # self.page_end = self.page_num
- # self.page_start = self.page_num - self.max_show
- # else:
- # self.page_start = self.current_page - self.half_show
- # # 页码最右边显示
- # self.page_end = self.current_page + self.half_show
- #
- #
- # import copy
- # self.params=copy.deepcopy(params) # {"page":"12","title_startwith":"py","id__gt":"5"}
- #
- #
- #
- # @property
- # def start(self):
- # # 数据从哪儿开始切
- # return (self.current_page - 1) * self.per_page
- #
- # @property
- # def end(self):
- # # 数据切片切到哪儿
- # return self.current_page * self.per_page
- #
- # def page_html(self):
- # # 生成页码
- # l = []
- # # 加一个首页
- # l.append('<li><a href="{}?page=1">首页</a></li>'.format(self.url_prefix))
- # # 加一个上一页
- # if self.current_page == 1:
- # l.append('<li class="disabled" ><a href="#">«</a></li>'.format(self.current_page))
- # else:
- # l.append('<li><a href="{}?page={}">«</a></li>'.format(self.url_prefix, self.current_page - 1))
- #
- #
- #
- # # {"page":"12","title_startwith":"py","id__gt":"5"} # "page=12&title_startwith=py&id__gt=5"
- #
- #
- # print(self.params.urlencode())
- # for i in range(self.page_start, self.page_end + 1):
- # self.params["page"]=i # # {"page":"7","title_startwith":"py","id__gt":"5"} # "page=7&title_startwith=py&id__gt=5"
- # if i == self.current_page:
- # tmp = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i)
- # else:
- # tmp = '<li><a href="{0}?{1}">{2}</a></li>'.format(self.url_prefix, self.params.urlencode(),i)
- # l.append(tmp)
- #
- #
- #
- #
- #
- #
- #
- # # 加一个下一页
- # if self.current_page == self.page_num:
- # l.append('<li class="disabled"><a href="#">»</a></li>'.format(self.current_page))
- # else:
- # l.append('<li><a href="{}?page={}">»</a></li>'.format(self.url_prefix, self.current_page + 1))
- # # 加一个尾页
- # l.append('<li><a href="{}?page={}">尾页</a></li>'.format(self.url_prefix, self.page_num))
- # return "".join(l)
############### 查看列表页面 ###############
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
- <script src="/static/js/jquery-1.12.4.min.js"></script>
- <style>
- .filter a{
- text-decoration: none;
- color: grey;
- }
- .active{
- color: rebeccapurple!important;
- }
- </style>
- </head>
- <body>
- <h4>数据列表</h4>
- <div class="container">
- <div class="row">
- <div class="col-md-9">
- <a href="{{ add_url }}" class="btn btn-primary">添加数据</a>
- {#搜索框,只有配置了search_fields才会展示#}
- {% if showlist.config.search_fields %}
- {#没有写method,默认是一个get请求#}
- <form action="" class="pull-right">
- <input class="form-control" style="display: inline-block;width:200px" type="text" name="q" value="{{ showlist.config.key_word }}"><button class="btn btn-default">search</button>
- </form>
- {% endif %}
- {#构建这个表单,就是为了批量操作的,因为需要下面的列表数据,所以包到一起, #}
- <form action="" method="post">
- {% csrf_token %}
- <select name="action" class="form-control" id="" style="width: 200px;margin: 8px 2px;display: inline-block;vertical-align: -1px">
- <option value="">---------------</option>
- {# get_action_list的结果:[{"name":""patch_init,"desc":"批量初始化"}]#}
- {#每一个item就是一个字段,#}
- {% for item in showlist.get_action_list %}
- <option value="{{ item.name }}">{{ item.desc }}</option>
- {% endfor %}
- </select><button type="submit" class="btn btn-success">Go</button>
- <table class="table table-bordered table-striped">
- {#表头#}
- <thead>
- <tr>
- {% for item in showlist.get_header %}
- <th>{{ item }}</th>
- {% endfor %}
- </tr>
- </thead>
- {#表数据#}
- <tbody>
- {% for data in showlist.get_body %}
- <tr>
- {% for item in data %}
- <td>{{ item }}</td>
- {% endfor %}
- </tr>
- {% endfor %}
- </tbody>
- </table>
- <nav class="pull-right">
- <ul class="pagination">
- {{ showlist.pagination.page_html|safe }}
- </ul>
- </nav>
- </form>
- </div>
- {#筛选#}
- <div class="col-md-3">
- {% if showlist.config.list_filter %}
- <div class="filter">
- <h4 style="">Filter</h4>
- {% for filter_field,linktags in showlist.get_filter_linktags.items %}
- <div class="well">
- <p>By {{ filter_field.upper }}</p>
- {% for link in linktags %}
- <p>{{ link|safe }}</p>
- {% endfor %}
- </div>
- {% endfor %}
- </div>
- {% endif %}
- </div>
- </div>
- </div>
- <script>
- $("#choice").click(function () {
- if($(this).prop("checked")){
- $(".choice_item").prop("checked",true)
- }else {
- $(".choice_item").prop("checked",false)
- }
- })
- </script>
- </body>
- </html>
############### 修改页面 ###############
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
- <script src="/static/js/jquery-1.12.4.min.js"></script>
- <style>
- input,select {
- display: block;
- width: 100%;
- height: 34px;
- padding: 6px 12px;
- font-size: 14px;
- line-height: 1.42857143;
- color: #555;
- background-color: #fff;
- background-image: none;
- border: 1px solid #ccc;
- border-radius: 4px;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
- -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
- -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
- transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
- }
- .error{
- color: red;
- }
- </style>
- </head>
- <body>
- <h3>编辑页面</h3>
- {% include 'form.html' %}
- </body>
- </html>
############### 删除页面 ###############
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- </head>
- <body>
- <h3>删除页面</h3>
- <form action="" method="post">
- {% csrf_token %}
- <button>确认删除?</button>
- <a href="{{ url }}">取消</a>
- </form>
- </body>
- </html>
############### 抽象form表单部分 ###############
- <div class="container">
- <div class="row">
- <div class="col-md-6 col-xs-8 col-md-offset-3">
- <form action="" method="post" novalidate>
- {% csrf_token %}
- {% for field in form %}
- <div style="position: relative">
- <label for="">{{ field.label }}</label>
- {{ field }} <span class=" error pull-right">{{ field.errors.0 }}</span>
- {% if field.is_pop %}
- {#如果是一个一对多多对多的字段,需要在字段的右侧放一个加号,需要弹出新的页面,来添加数据#}
- {#position,设置标签的位置,父标签是相对定位,子标签是绝对定位,#}
- {#你怎么知道一个字段是一对多多对多的字段??,根据字段的类型,如果是一对多,多对多,加一个is_pop的字段为true#}
- {#绑定一个点击事件,点击要跳转到一个url,#}
- <a onclick="pop('{{ field.url }}')" style="position: absolute;right: -30px;top: 20px"><span style="font-size: 28px">+</span></a>
- {% endif %}
- </div>
- {% endfor %}
- <button type="submit" class="btn btn-default pull-right">提交</button>
- </form>
- </div>
- </div>
- </div>
- <script>
- function pop(url) {
- {#点击之后弹出一个窗口,路径是传入的url,#}
- window.open(url,"","width=600,height=400,top=100,left=100")
- {#top=100,left=100,控制弹出窗口的位置,大小,#}
- }
- </script>
############### 新增页面 ###############
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
- <script src="/static/js/jquery-1.12.4.min.js"></script>
- <style>
- input,select {
- display: block;
- width: 100%;
- height: 34px;
- padding: 6px 12px;
- font-size: 14px;
- line-height: 1.42857143;
- color: #555;
- background-color: #fff;
- background-image: none;
- border: 1px solid #ccc;
- border-radius: 4px;
- -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
- box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
- -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
- -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
- transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
- }
- .error{
- color: red;
- }
- </style>
- </head>
- <body>
- <h3>添加页面</h3>
- {% include 'form.html' %}
- <script>
- function pop_response (pk,text,id) {
- {#添加内容之后,返回的时候能自动带回到页面,#}
- console.log(pk,text,id);
- // 选择哪一个select标签
- // option的文本值和value值
- var $option=$('<option>'); // <option></option>
- $option.html(text); // <option>南京出版社</option>
- $option.val(pk); // <option value=111>南京出版社</option>
- $option.attr("selected","selected") ; // <option value=111>南京出版社</option>
- $("#"+id).append($option)
- }
- </script>
- </body>
- </html>
############### pop页面 ###############
- <!DOCTYPE html>
- <html lang="zh-CN">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- <meta name="viewport" content="width=device-width, initial-scale=1">
- </head>
- <body>
- <script>
- {#这个pop_response是自己定义的#}
- window.opener.pop_response('{{ res.pk }}',"{{ res.text }}",'{{ res.pop_res_id }}')
- window.close()
- </script>
- </body>
- </html>
############### admin ###############
############### admin ###############
crm项目-stark组件的更多相关文章
- crm项目-stark组件分析
############### stark组件 ################ """ 这个stark组件是非常神奇的 1,独立的一个组件 2,没有mod ...
- day 70 crm(7):stark组件调用,以及权限分配
前情提要: 复习: 1: orm !!!!! 2: session 3: django 4: 前端在复习 5: 复习中间件 学习的stark 的组件调用,以及权限的应用 一:权限的概念, 1: ...
- crm 使用stark组件
# Create your models here. from django.db import models class Department(models.Model): "" ...
- day67 crm(4) stark组件的增删改 以及 model_from使用和from组件回顾
前情提要:Django stark 组件开发的 增删改, model_form组件的使用 form组件的回顾 一:list_display_link 创建 功能描述: 使包含的字段能 ...
- crm项目-权限组件
############### 表结构分析 ################ """ 表结构设计: 1,四张表 用户表,userinfo,这个表本身不会被创 ...
- CRM项目之stark组件
. stark也是一个app(用startapp stark创建),目标时把这个做成一个可以拔插的组件 . setting文件下INSTALLED_APPS 路径要配置好(app的注册) . 写好si ...
- CRM项目之stark组件(2)
那么从今天开始呢,我们就要开始设计属于我们自己的admin组件,起个名字就叫stark吧(当然你愿意叫什么都可以). stark组件之四步走 仿照admin组件实现流程,stark组件要实现四件事情: ...
- crm项目之stark组件前戏(二)
stark组件的设计主要来源于django中admin的功能,在django admin中只需要将模型表进行注册,就可以在页面对该表进行curd的动作,那么django admin是如何做的呢? 在d ...
- CRM项目之RBAC权限组件-day26
写在前面 上课第26天,打卡: 世间安得双全法 不负如来不负卿 s17day26 CRM项目 项目概要:XX公司CRM - 权限管理,公共组件,app ***** - 熟悉增删改查,Low *** - ...
随机推荐
- sonarqube linux安装总结,集成jenkins
第一条建议,安装sonarqube首先看好版本号,不同版本号的安装配置可能不同,如果你想走捷径,看官网对应发布的安装使用教程.https://www.sonarqube.org/downloads/ ...
- Nginx和php交互的两种方式
Unix socket 也叫IPC socket 也就是进程间通信套接字用于同一台主机上的不同进程间交换数据 TCP socket IP socket要利用主机的传输层(tcp),可以用于同一台主机 ...
- UML-UML工具与UML蓝图
1.UML应用场景 1).UML作为草图 2).UML作为蓝图. UML生成java代码(前向工程) java代码生成UML(逆向工程) 2.如果绘制了UML草图,如何在编码后更新该图形? 逆向工程, ...
- 实现3d效果
transform-origin: center left 60px;可以实现3d转换
- 苹果下架2.5万赌博APP!一场净化风暴正在迅速成型
当下智能手机发展得如火如荼,但对于大众来说,体验终究还是要落到包罗万千的APP上.APP身为智能手机的灵魂,全面渗入了大众的工作.生活.娱乐.学习等多个方面.每一个APP的背后,其实都在打开着一扇通往 ...
- vue接口交互写死的
vue接口 写死的 RoleOfUserOrgRef: function ({ commit }, param) { return new Promise((resolve) => { $axi ...
- Spring Cloud服务间调用鉴权
学习使用Spring Cloud 微服务间的调用都是RestFul风格,如何保证调用之间的安全性,这是一个很重要的问题. 通过查阅资料http://wiselyman.iteye.com/blog/2 ...
- UML-交互图包含哪些图?
猫比狗精明,但你无法让8只猫在雪地里拉雪橇---杰夫.瓦尔德斯 本章是重点. 1.总览 2.顺序图 1).类A具有doOne方法和类B的属性 2).doOne方法中调用类B的doTwo()和doThr ...
- HDU 1257最少拦截系统[动态规划]
传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1257 最 ...
- nm命令介绍
一.参考文章 网址1:https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/nm.html 参考2: man nm 参考3:<linux ...