###############  admin基本认识和常用的定制功能    ###############

  1. stark组件
  2.  
  3. admin的基本认识
  4. 1,就是一个app,嵌入到了django里面,你可以在settings中看到
  5. 2,就是一个web后台管理工具,使用它可以更加的方便
  6. 3,通常我们在生成项目时会在 urls.py 中自动设置好url访问路径
  7. urlpatterns = [
  8. url(r'^admin/', admin.site.urls)
  9. ]
  10. 4,启动开发服务器,然后在浏览器中访问 http://127.0.0.1:8000/admin/
  11. 5,你通过命令 python manage.py createsuperuser 来创建超级用户
  12. 6,使用的时候先注册数据模型:admin.site.register(models.UserInfo)
  13. 7,点击进入会展示数据,默认就是把这个对象打印出来,复杂的,需要定制的,需要利用ModelAdmin进行操作
  14. class CourseConfig(admin.ModelAdmin):
  15. pass
  16. admin.site.register(Course,CourseConfig)
  17.  
  18. #######################
  19.  
  20. class UserInfoConfig(admin.ModelAdmin):
  21. list_display=["id","name","username","password","email","depart"] # 定制显示的列。不能放多对多的字段
  22. list_display_links=["username"] # 定制列可以点击跳转到详情页面,
  23. list_filter=["depart"] # 定制右侧快速筛选。
  24. list_editable=["email"] # 可以编辑的列,可以编辑就不能是list_display_links字段了,
  25. search_fields=["username"] # 模糊搜索的功能
  26.  
  27. # 定义action的函数
  28. def func(self,request,queryset):
  29. print(request,queryset)
  30. queryset.update(email="1212@qq.com")
  31. func.short_description = "批量初始化操作"
  32.  
  33. actions=[func,] # 定制action中的操作
  34. fields=["username"] # 查看详情和新增页面,可以控制显示的字段
  35. ordering=["-id"] # 数据排序规则,倒序在字段前面加符号,
  36.  
  37. admin.site.register(UserInfo,UserInfoConfig)

###############  admin的url设计的基础知识点   ###############

  1. adminurl是怎么设计的,这是核心,
  2. urlpatterns = [
  3. url(r'^admin/', admin.site.urls), # 为什么这一句能能够生成多条url,
  4. ]

第一个知识点,url的嵌套使用

  1. def yuan(request):
  2. return HttpResponse("Yuan")
  3.  
  4. def test01(request):
  5. return HttpResponse("test01")
  6.  
  7. def test02(request):
  8. return HttpResponse("test02")
  9.  
  10. def test03(request):
  11. return HttpResponse("test03")
  12.  
  13. def test04(request):
  14. return HttpResponse("test04")
  15.  
  16. def test05(request):
  17. return HttpResponse("test05")
  18.  
  19. urlpatterns = [
  20. url(r'^admin/', admin.site.urls),
  21. url(r'^yuan/', ([
  22. url(r'^test01/', ([
  23. url(r'^test04/', test04), # http://127.0.0.1:8000/yuan/test01/test04/
  24. url(r'^test05/', test05),
  25. ], None, None)),
  26. url(r'^test02/', test02),
  27. url(r'^test03/', test03),
  28. ], None, None))
  29. ]

第二个知识点:单例模式,

  1. # 单例模式
  2.  
  3. # 一个类只允许实例一个对象
  4.  
  5. # class Singleton(object):
  6. # _instance = None
  7. # def __new__(cls, *args, **kw):
  8. # if not cls._instance:
  9. # cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)
  10. # return cls._instance
  11. #
  12. # class MyClass(Singleton):
  13. # a = 1
  14. #
  15. #
  16. # one = MyClass()
  17. # one.a=3
  18. #
  19. # two = MyClass()
  20. # print(two.a) # 这个地方就是3,因为one和two指向的同一个内存空间,one改掉了a=3,所以two取值的时候就是3
  21. #
  22. # # print(one==two)
  23. # # print(id(one),id(two))
  24.  
  25. # 第二种方法
  26. ###########################
  27. # 第一个文件
  28. class My_Singleton(object):
  29. x =12
  30. def foo(self):
  31. print(self.x)
  32. my_singleton = My_Singleton() # 这是一个关键的一步
  33.  
  34. print("OK")
  35.  
  36. ###################
  37. # 第二个文件
  38. from mysingleton import my_singleton
  39. def foo():
  40. print(id(my_singleton))
  41. ############
  42. # 第三个文件
  43. from mysingleton import my_singleton,My_Singleton
  44.  
  45. # a=My_Singleton()
  46. # b=My_Singleton()
  47. #
  48. # print(id(a))
  49. # print(id(b)) # 这是拿的类对象,而不是实例对象,所以,这两个不一样,
  50.  
  51. print(id(my_singleton))
  52. from mysingleton import my_singleton
  53. print(id(my_singleton))
  54. from func import *
  55. foo() # 这三次都是拿的实例对象,所以id的结果都是一样的,

############### admin的url设计    ###############

第一个注册:

  1. # 注册
  2.  
  3. self._registry = {}
  4. self._registry[model] = admin_class(model, self)
  5. # 注册的时候,是定义了一个字典,然后以model表为键,以对应的自定义类为值,生成对应的字典,

第二个url设置

  1. def add(request):
  2. return HttpResponse("add")
  3. def delete(request,id):
  4. return HttpResponse("delete")
  5. def change(request,id):
  6. return HttpResponse("change")
  7. def list_view(request):
  8. return HttpResponse("list_view")
  9.  
  10. def get_urls2():
  11.  
  12. temp=[]
  13. temp.append(url(r"^add/",add))
  14. temp.append(url(r"^(\d+)/delete/",delete))
  15. temp.append(url(r"^(\d+)/change/",change))
  16. temp.append(url(r"^$",list_view))
  17. print("temp2",temp)
  18. # [
  19. # <RegexURLPattern None ^add/>,
  20. # <RegexURLPattern None ^(\d+)/delete/>,
  21. # <RegexURLPattern None ^(\d+)/change/>,
  22. # <RegexURLPattern None ^$>
  23. # ]
  24. return temp
  25.  
  26. def get_urls():
  27.  
  28. temp=[]
  29. print("_registry",admin.site._registry)
  30.  
  31. for model,admin_class_obj in admin.site._registry.items():
  32. print("model",model) # 所有的注册模型表
  33.  
  34. # < class 'app01.models.Book'>-----> "book" "app01"
  35. # < class 'app01.models.Room'>-----> "room" "app01"
  36. print("===>",model._meta.model_name)
  37. print("===>",model._meta.app_label)
  38.  
  39. model_name=model._meta.model_name # 对应的model表的名字
  40. app_label=model._meta.app_label # 对应的app名字
  41. temp.append(url(r"%s/%s/"%(app_label,model_name),(get_urls2(),None,None)))
  42. print("temp",temp)
  43. """
  44. [
  45. <RegexURLResolver <RegexURLPattern list> (None:None) auth/group/>,
  46. <RegexURLResolver <RegexURLPattern list> (None:None) auth/user/>,
  47. <RegexURLResolver <RegexURLPattern list> (None:None) crm/userinfo/>
  48. ]
  49. """
  50.  
  51. return temp
  52.  
  53. urlpatterns = [
  54. url(r'^admin/', admin.site.urls),
  55. url(r'^yuan/', (get_urls(), None, None))
  56. ]

###############  模仿admin-stark组件的url设计    ###############

  1. class ModelStark(object):
  2.  
  3. def __init__(self,model,site):
  4. self.model=model # 谁调用的就是那个表
  5. self.site=site
  6.  
  7. def add_view(self, request):
  8. return HttpResponse("add_view")
  9.  
  10. def change_view(self, request, id):
  11. return HttpResponse("change_view")
  12.  
  13. def delete_view(self, request, id):
  14. return HttpResponse("delete_view")
  15.  
  16. def list_view(self, request):
  17. return HttpResponse("list_view")
  18.  
  19. def get_urls_2(self):
  20.  
  21. temp = []
  22.  
  23. model_name=self.model._meta.model_name
  24. app_label=self.model._meta.app_label
  25.  
  26. temp.append(url(r"^add/", self.add_view))
  27. temp.append(url(r"^(\d+)/delete/", self.delete_view))
  28. temp.append(url(r"^(\d+)/change/", self.change_view))
  29. temp.append(url(r"^$", self.list_view))
  30.  
  31. return temp
  32.  
  33. @property
  34. def urls_2(self):
  35. print(self.model)
  36. return self.get_urls_2(), None, None
  37.  
  38. class StarkSite(object):
  39. def __init__(self):
  40. self._registry={}
  41.  
  42. def register(self,model,stark_class=None):
  43. if not stark_class:
  44. stark_class=ModelStark
  45.  
  46. self._registry[model] = stark_class(model, self) # 括号内的两个参数,就是ModelStark默认的两个参数,self就是site
  47.  
  48. def get_urls(self):
  49. temp=[]
  50. for model,stark_class_obj in self._registry.items():
  51. model_name=model._meta.model_name
  52. app_label=model._meta.app_label
  53. # 分发增删改查
  54. temp.append(url(r"^%s/%s/"%(app_label,model_name),stark_class_obj.urls_2))
  55.  
  56. '''
  57. url(r"^app01/userinfo/",UserConfig(Userinfo).urls_2),
  58. url(r"^app01/book/",ModelStark(Book).urls_2),
  59.  
  60. '''
  61. return temp
  62.  
  63. @property
  64. def urls(self):
  65. return self.get_urls(),None,None
  66.  
  67. site=StarkSite() # 单例模式

##############  stark组件需要实现的功能    ###############

  1. 在完成了注册和url设计之后,stark组件需要完成什么功能
  2.  
  3. 1,查询页面
  4. 1.1 表头展示,可以定制展示的列,
  5. 1.2 表内容展示,删除 编辑,复选框的功能
  6. 1.3 查询功能,可以定义查询的字段,
  7. 1.4 action功能,可以定制批量操作
  8. 1.5 筛选功能,可以定制筛选的字段,
  9. 1.6 分页功能
  10. 这是最为复杂的部分,
  11.  
  12. 2,新增页面
  13. 2.1 一个重要的pop功能,
  14.  
  15. 3,删除页面
  16. 这个简单
  17.  
  18. 4,编辑页面,
  19. 这个简单,和新增页面很相似,只需要把要编辑的数据带到页面展示,
  20.  
  21. 整个重写,使用到了
  22. 1django
  23. 2admin
  24. 3,前端,jshtmlbootstrapjQuery

##############  stark-service    ###############

  1. # by luffycity.com
  2. from django.conf.urls import url
  3.  
  4. from django.shortcuts import HttpResponse,render,redirect
  5. from django.urls import reverse
  6. from django.db.models import Q
  7. from django.utils.safestring import mark_safe
  8.  
  9. from stark.utils.page import Pagination
  10. from django.db.models.fields.related import ManyToManyField,ForeignKey
  11. class ShowList(object):
  12. def __init__(self,config,data_list,request):
  13. self.config=config # 这里的config就是用来接收传递的modelstark类的,下面就可以使用config调用modelstark里面的方法了,
  14. self.data_list=data_list # 这个datalist是需要展示的数据
  15. self.request=request # 为什么需要传递request?因为需要在这个里面获取page参数,是第几页
  16. #分页
  17. data_count=self.data_list.count()
  18. current_page=int(self.request.GET.get("page",1))
  19. base_path=self.request.path
  20.  
  21. self.pagination=Pagination(current_page,data_count,base_path,self.request.GET,per_page_num=10, pager_count=11, )
  22. self.page_data=self.data_list[self.pagination.start:self.pagination.end]
  23.  
  24. # actions
  25. self.actions=self.config.new_actions() # [patch_init,] # 获取modelstark中配置的action列表,
  26.  
  27. def get_filter_linktags(self):
  28. print("list_filter:",self.config.list_filter)
  29. link_dic={} # 格式是{筛选字段1:筛选值1,筛选字段2:筛选值2}
  30. import copy
  31.  
  32. for filter_field in self.config.list_filter: # ["title","publish","authors",]
  33. params = copy.deepcopy(self.request.GET) # 复制一份方便操作
  34.  
  35. cid=self.request.GET.get(filter_field,0) # 这是获取到前端拼接的id,
  36.  
  37. print("filter_field",filter_field) # "publish"
  38. filter_field_obj=self.config.model._meta.get_field(filter_field) # 这是拿到的字段对象
  39. print("filter_field_obj",filter_field_obj)
  40. print(type(filter_field_obj))
  41. from django.db.models.fields.related import ForeignKey
  42. from django.db.models.fields.related import ManyToManyField
  43. # 举例说明:拿到出版社关联的书籍,筛选是所有关联的出版社,拿到作者关联的书籍,筛选是所有关联的作者,怎么获取?
  44. print("rel======...",filter_field_obj.rel)
  45.  
  46. if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):
  47. data_list=filter_field_obj.rel.to.objects.all()# publish1,publish2...】
  48. # filter_field_obj.rel.to,这种特殊写法,只有字段有关联表的时候才有意义,一对多,和多对多的,
  49. else:
  50. data_list=self.config.model.objects.all().values("pk",filter_field)
  51. print("data_list",data_list)
  52.  
  53. temp=[]
  54. # 处理全部标签
  55. if params.get(filter_field): # filter_field 这是筛选的字段,如果有筛选值,就删掉,
  56. del params[filter_field]
  57. temp.append("<a href='?%s'>全部</a>"%params.urlencode())
  58. else:
  59. temp.append("<a class='active' href='#'>全部</a>")
  60.  
  61. # 处理数据标签
  62. for obj in data_list:
  63. if isinstance(filter_field_obj,ForeignKey) or isinstance(filter_field_obj,ManyToManyField):
  64. pk=obj.pk
  65. text=str(obj)
  66. params[filter_field] = pk
  67. else: # data_list= [{"pk":1,"title":"go"},....]
  68. print("========")
  69. pk=obj.get("pk")
  70. text=obj.get(filter_field)
  71. params[filter_field] =text # 处理单表查询
  72.  
  73. _url=params.urlencode()
  74. if cid==str(pk) or cid==text: # 这是为了实现点击选中的标签,展示深蓝色,active
  75. link_tag="<a class='active' href='?%s'>%s</a>"%(_url,text)
  76. else:
  77. link_tag = "<a href='?%s'>%s</a>" % (_url, text)
  78. temp.append(link_tag)
  79.  
  80. link_dic[filter_field]=temp
  81.  
  82. return link_dic
  83.  
  84. def get_action_list(self): # 拿到action操作,放到页面去渲染
  85. temp=[]
  86. for action in self.actions: # 这是配置的action列表,循环这个列表,每一个action就是每一个函数,
  87. temp.append({
  88. "name":action.__name__, # 获取函数的名字,作为值
  89. "desc":action.short_description # 获取函数的描述,作为展示short_description,这是函数的一个动态属性
  90. }) # [{"name":""patch_init,"desc":"批量初始化"}]
  91.  
  92. print("temp",temp)
  93. return temp
  94.  
  95. def get_header(self):
  96. # 构建表头
  97. header_list = []
  98. print("header",
  99. self.config.new_list_play()) # [checkbox,"pk","name","age",edit ,deletes] 【checkbox ,"__str__", edit ,deletes】
  100.  
  101. for field in self.config.new_list_play():
  102.  
  103. if callable(field):
  104. # header_list.append(field.__name__) # field.__name__函数的名字
  105. val = field(self.config, header=True) # header=True,header默认是false,这个再去拿值的之后就会拿到汉字了
  106. header_list.append(val)
  107.  
  108. else:
  109. if field == "__str__": # 这是没有自定义的情况
  110. header_list.append(self.config.model._meta.model_name.upper()) # 这是展示表名的大写作为表头
  111. else: # 这是自定义的情况
  112. # header_list.append(field)
  113. val = self.config.model._meta.get_field(field).verbose_name # 这是获取到了表里面的字段,verbose_name这是字段的中文
  114. header_list.append(val)
  115. return header_list
  116.  
  117. def get_body(self):
  118. # 构建表单数据
  119. new_data_list = []
  120. for obj in self.page_data:
  121. temp = []
  122.  
  123. for filed in self.config.new_list_play(): # ["__str__",] ["pk","name","age",edit] 这一步应该把编辑,删除,复选框都加进来了
  124.  
  125. if callable(filed): # callable判断是否是一个可调用的,如果是一个字符串就是False,如果是一个方法就是true
  126. print("obj-----:",obj)
  127. val = filed(self.config, obj)
  128. else:
  129. try:
  130. field_obj=self.config.model._meta.get_field(filed)
  131. if isinstance(field_obj,ManyToManyField): # 多对多的时候如何展示数据
  132. ret = getattr(obj,filed).all() # 这是获取到多对多的情况,可能会有多个值,
  133. t=[]
  134. for mobj in ret:
  135. t.append(str(mobj))
  136. val=",".join(t) # 拼成逗号隔开的样子,展示出来,
  137. else:
  138. print("====>",field_obj.choices)
  139. if field_obj.choices:
  140. val = getattr(obj, "get_"+filed+"_display") # 这个obj是每一条数据,filed是每一条数据应该显示的字段,
  141. else:
  142. val = getattr(obj, filed)
  143. if filed in self.config.list_display_links: # 如果是一个可以点击的字段,要特殊处理成为超链接
  144. # "app01/userinfo/(\d+)/change"
  145. _url = self.config.get_change_url(obj)
  146. val = mark_safe("<a href='%s'>%s</a>" % (_url, val))
  147.  
  148. except Exception as e:
  149. val = getattr(obj, filed)
  150.  
  151. temp.append(val)
  152.  
  153. new_data_list.append(temp)
  154. return new_data_list
  155.  
  156. '''
  157. [
  158. [1,"alex",12],
  159. [1,"alex",12],
  160. [1,"alex",12],
  161. [1,"alex",12],
  162.  
  163. ]
  164.  
  165. '''
  166.  
  167. class ModelStark(object):
  168.  
  169. list_display=["__str__",]
  170. list_display_links=[]
  171. modelform_class=None
  172. search_fields=[]
  173. actions = []
  174. list_filter=[]
  175.  
  176. def patch_delete(self, request, queryset):
  177. """批量删除"""
  178. queryset.delete()
  179.  
  180. patch_delete.short_description = "批量删除"
  181.  
  182. def __init__(self,model,site):
  183. self.model=model
  184. self.site=site
  185.  
  186. # 删除 编辑,复选框
  187. def edit(self,obj=None,header=False):
  188. if header:
  189. return "操作"
  190. #return mark_safe("<a href='%s/change'>编辑</a>"%obj.pk)
  191. _url=self.get_change_url(obj)
  192.  
  193. return mark_safe("<a href='%s'>编辑</a>"%_url)
  194.  
  195. def deletes(self,obj=None,header=False):
  196. if header:
  197. return "操作"
  198. # return mark_safe("<a href='%s/change'>编辑</a>"%obj.pk)
  199.  
  200. _url=self.get_delete_url(obj)
  201.  
  202. return mark_safe("<a href='%s'>删除</a>" % _url)
  203.  
  204. def checkbox(self,obj=None,header=False):
  205. if header:
  206. return mark_safe('<input id="choice" type="checkbox">')
  207.  
  208. return mark_safe('<input class="choice_item" type="checkbox" name="selected_pk" value="%s">'%obj.pk)
  209. # 这一步非常的重要,因为在配合action去取到选中的数据,
  210.  
  211. def get_modelform_class(self):
  212. """如果客户定制了用客户定制的,如果没有没有定制使用默认的,"""
  213. if not self.modelform_class:
  214. from django.forms import ModelForm # 这个涉及到了form表单的内容,
  215. from django.forms import widgets as wid
  216. class ModelFormDemo(ModelForm): # 可以在每一个app中的stark里面,对每一个model进行重写这个类,就可以定制了
  217. class Meta:
  218. model = self.model
  219. fields = "__all__"
  220. labels={
  221. ""
  222. } # 可以在每一个app中的stark里面,labels可以对字段进行设置汉字,格式是键:值的方式,
  223. return ModelFormDemo
  224. else:
  225. return self.modelform_class
  226.  
  227. def get_new_form(self,form):
  228. """这是pop弹出的窗口对象的方法,"""
  229. for bfield in form:
  230. from django.forms.boundfield import BoundField
  231. print(bfield.field) # 字段对象
  232. print("name",bfield.name) # 字段名(字符串)
  233. print(type(bfield.field)) # 字段类型
  234. from django.forms.models import ModelChoiceField
  235. if isinstance(bfield.field,ModelChoiceField):
  236. bfield.is_pop=True # 这是动态给多对多的字段加属性
  237. # 怎么拿到关联表的名字,和它所属的APP呢,
  238. print("=======>",bfield.field.queryset.model) # 一对多或者多对多字段的关联模型表
  239. related_model_name=bfield.field.queryset.model._meta.model_name
  240. related_app_label=bfield.field.queryset.model._meta.app_label
  241.  
  242. _url=reverse("%s_%s_add"%(related_app_label,related_model_name)) # 反向解析进入对应的添加页面,
  243. bfield.url=_url+"?pop_res_id=id_%s"%bfield.name # 动态加字段,字段名(字符串)
  244.  
  245. return form
  246.  
  247. def add_view(self, request):
  248. ModelFormDemo = self.get_modelform_class() # 这是返回一个类
  249. form = ModelFormDemo() # 使用这个类实例化一个对象出来,
  250.  
  251. form=self.get_new_form(form)
  252.  
  253. if request.method=="POST": # 点击提交按钮要做的事情
  254. form = ModelFormDemo(request.POST)
  255. if form.is_valid():
  256. obj=form.save() # 这都是form表单的功能,校验通过就保存到数据库,
  257.  
  258. pop_res_id=request.GET.get("pop_res_id")
  259.  
  260. if pop_res_id:
  261. res ={"pk":obj.pk,"text":str(obj),"pop_res_id":pop_res_id}
  262. import json
  263. return render(request, "pop.html", {"res":res})
  264. else:
  265. return redirect(self.get_list_url())
  266. print("locals()",locals())
  267. """
  268. {
  269. '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)>,
  270. 'ModelFormDemo': <class 'stark.service.stark.ModelStark.get_modelform_class.<locals>.ModelFormDemo'>,
  271. 'request': <WSGIRequest: GET '/stark/crm/customer/add/'>,
  272. 'self': <crm.stark.CusotmerConfig object at 0x000000000D1FBC18>
  273. }
  274. """
  275. return render(request, "add_view.html", locals()) # Python 的内建函数 locals() 。它返回的字典对所有局部变量的名称与值进行映射。
  276.  
  277. def delete_view(self, request, id):
  278. url = self.get_list_url()
  279. if request.method=="POST":
  280. self.model.objects.filter(pk=id).delete()
  281. return redirect(url)
  282.  
  283. return render(request, "delete_view.html", locals())
  284.  
  285. def change_view(self, request, id):
  286. ModelFormDemo = self.get_modelform_class() # 获取这个类,可以控制展示的字段等信息
  287. print("=====id",id)
  288. edit_obj = self.model.objects.filter(pk=id).first()
  289.  
  290. if request.method=="POST":
  291. form = ModelFormDemo(request.POST,instance=edit_obj) # 这个instance也是djangoform表单的功能,
  292. if form.is_valid():
  293. form.save()
  294. return redirect(self.get_list_url()) # 提交之后返回到列表页
  295.  
  296. print("locals()",locals())
  297. return render(request, "change_view.html", locals())
  298.  
  299. print("***********",edit_obj)
  300. form = ModelFormDemo(instance=edit_obj) # 和新增页面一样,只需要加一个instance
  301. form = self.get_new_form(form)
  302.  
  303. return render(request, "change_view.html", locals())
  304.  
  305. def new_list_play(self):
  306. """这个方法不只是把每一条数据的字段放进来了,还把编辑,删除,复选框也放进来了,"""
  307. temp=[]
  308. temp.append(ModelStark.checkbox) # 复选框加入
  309. temp.extend(self.list_display) # 自定义字段加入,这个地方还可以自己自定义函数,传进来,
  310. if not self.list_display_links: # 如果已经有点击链接可以编辑的入口了,就不需要编辑这一栏了,
  311. temp.append(ModelStark.edit) # 编辑加入
  312. temp.append(ModelStark.deletes) # 删除加入
  313. return temp
  314.  
  315. def new_actions(self):
  316. temp=[]
  317. temp.append(ModelStark.patch_delete)
  318. temp.extend(self.actions) # 这个里面就可能会有自定义的action,这样组成一个新的action,
  319.  
  320. return temp
  321.  
  322. def get_change_url(self,obj): # 这一个功能多个地方使用,所以封装到一个方法里面,
  323. model_name = self.model._meta.model_name
  324. app_label = self.model._meta.app_label
  325. print("obj===========",obj)
  326. # from django.urls import reverse,这个是django中的一个工具
  327. _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) # 反向解析,args,是传入的id字段,
  328.  
  329. return _url
  330.  
  331. def get_delete_url(self, obj):
  332. model_name = self.model._meta.model_name
  333. app_label = self.model._meta.app_label
  334.  
  335. _url = reverse("%s_%s_delete" % (app_label, model_name), args=(obj.pk,))
  336.  
  337. return _url
  338.  
  339. def get_add_url(self):
  340.  
  341. model_name = self.model._meta.model_name
  342. app_label = self.model._meta.app_label
  343.  
  344. _url = reverse("%s_%s_add" % (app_label, model_name))
  345.  
  346. return _url
  347.  
  348. def get_list_url(self):
  349.  
  350. model_name = self.model._meta.model_name
  351. app_label = self.model._meta.app_label
  352.  
  353. _url = reverse("%s_%s_list" % (app_label, model_name))
  354.  
  355. return _url
  356.  
  357. def get_serach_conditon(self,request):
  358. key_word = request.GET.get("q","")
  359. self.key_word=key_word # 这是给modelstark加一个实例对象,然后在查询之后就可以直接把查询内容渲染到页面了,通过showlist.config.keyword
  360.  
  361. search_connection = Q() # 默认这个是空的条件
  362. if key_word:
  363. # self.search_fields # ["title","price"]
  364. search_connection.connector = "or" # 这是orm使用q查询的另外一种方法,
  365. for search_field in self.search_fields:
  366. search_connection.children.append((search_field + "__contains", key_word))
  367. print("search_connection",search_connection)
  368. return search_connection
  369.  
  370. def get_filter_condition(self,request):
  371. filter_condition=Q()
  372.  
  373. for filter_field,val in request.GET.items():# courserecord=2
  374. if filter_field !="page": # 把page这个去掉,不加入过滤
  375. filter_condition.children.append((filter_field,val))
  376.  
  377. return filter_condition
  378.  
  379. def list_view(self, request):
  380. if request.method=="POST": # 这个post请求,就是在处理action的提交(go)
  381. print("POST:",request.POST) # 把input框的值传过来了,把select下面的选中的值传过来,可以在post中取到action和selected_pk
  382. action=request.POST.get("action") # patch_init
  383. selected_pk=request.POST.getlist("selected_pk")
  384. action_func=getattr(self,action) # 反射,从self中去找action,action这是一个变量,是对应的点击的哪一个函数
  385. # self,是配置类,如果没有找到就去父类找,
  386. queryset=self.model.objects.filter(pk__in=selected_pk)
  387. ret=action_func(request,queryset) # 调用对应的函数操作,
  388.  
  389. #return ret
  390.  
  391. # 获取serach的Q对象
  392. search_connection=self.get_serach_conditon(request)
  393.  
  394. # 获取filter构建Q对象
  395.  
  396. filter_condition=self.get_filter_condition(request)
  397.  
  398. print("search_connection",search_connection,"filter_condition",filter_condition)
  399.  
  400. # 筛选获取当前表所有数据
  401. data_list=self.model.objects.all().filter(search_connection).filter(filter_condition) # 【obj1,obj2,....】
  402.  
  403. print("data_list",data_list)
  404. # 按这ShowList展示页面
  405. showlist=ShowList(self,data_list,request) # 实例化一个showlist,这个self就是现在的modelstark类,需要作为一个参数传递,
  406.  
  407. # 构建一个查看URL
  408. add_url=self.get_add_url()
  409. return render(request, "list_view.html", locals())
  410.  
  411. def extra_url(self):
  412.  
  413. return []
  414.  
  415. def get_urls_2(self):
  416.  
  417. temp = []
  418.  
  419. model_name=self.model._meta.model_name
  420. app_label=self.model._meta.app_label
  421.  
  422. temp.append(url(r"^add/", self.add_view,name="%s_%s_add"%(app_label,model_name))) # 这个name用来反向解析用
  423. temp.append(url(r"^(\d+)/delete/", self.delete_view,name="%s_%s_delete"%(app_label,model_name)))
  424. temp.append(url(r"^(\d+)/change/", self.change_view,name="%s_%s_change"%(app_label,model_name)))
  425. temp.append(url(r"^$", self.list_view,name="%s_%s_list"%(app_label,model_name)))
  426.  
  427. # 扩展url
  428. temp.extend(self.extra_url())
  429.  
  430. return temp
  431.  
  432. @property
  433. def urls_2(self):
  434. print(self.model)
  435. return self.get_urls_2(), None, None
  436.  
  437. class StarkSite(object):
  438. def __init__(self):
  439. self._registry={}
  440.  
  441. def register(self,model,stark_class=None):
  442. if not stark_class:
  443. stark_class=ModelStark
  444.  
  445. self._registry[model] = stark_class(model, self) # 括号内的两个参数,就是ModelStark默认的两个参数,self就是site
  446.  
  447. def get_urls(self):
  448. temp=[]
  449. for model,stark_class_obj in self._registry.items():
  450. model_name=model._meta.model_name
  451. app_label=model._meta.app_label
  452. # 分发增删改查
  453. temp.append(url(r"^%s/%s/"%(app_label,model_name),stark_class_obj.urls_2))
  454.  
  455. '''
  456. url(r"^app01/userinfo/",UserConfig(Userinfo).urls_2),
  457. url(r"^app01/book/",ModelStark(Book).urls_2),
  458.  
  459. '''
  460. return temp
  461.  
  462. @property
  463. def urls(self):
  464. return self.get_urls(),None,None
  465.  
  466. site=StarkSite()

###############  stark-分页      ###############

  1. """
  2. 自定义分页组件
  3.  
  4. """
  5.  
  6. class Pagination(object):
  7. def __init__(self, current_page, all_count, base_url,params, per_page_num=8, pager_count=11, ):
  8. """
  9. 封装分页相关数据
  10. :param current_page: 当前页
  11. :param all_count: 数据库中的数据总条数
  12. :param per_page_num: 每页显示的数据条数
  13. :param base_url: 分页中显示的URL前缀
  14. :param pager_count: 最多显示的页码个数
  15. """
  16.  
  17. try:
  18. current_page = int(current_page)
  19. except Exception as e:
  20. current_page = 1
  21.  
  22. if current_page < 1:
  23. current_page = 1
  24.  
  25. self.current_page = current_page
  26.  
  27. self.all_count = all_count
  28. self.per_page_num = per_page_num
  29.  
  30. self.base_url = base_url
  31.  
  32. # 总页码
  33. all_pager, tmp = divmod(all_count, per_page_num)
  34. if tmp:
  35. all_pager += 1
  36. self.all_pager = all_pager
  37.  
  38. self.pager_count = pager_count # 最多显示页码数
  39. self.pager_count_half = int((pager_count - 1) / 2)
  40.  
  41. import copy
  42. params = copy.deepcopy(params)
  43. params._mutable = True
  44. self.params = params # self.params : {"page":77,"title":"python","nid":1}
  45.  
  46. @property
  47. def start(self):
  48. return (self.current_page - 1) * self.per_page_num
  49.  
  50. @property
  51. def end(self):
  52. return self.current_page * self.per_page_num
  53.  
  54. def page_html(self):
  55. # 如果总页码 < 11个:
  56. if self.all_pager <= self.pager_count:
  57. pager_start = 1
  58. pager_end = self.all_pager + 1
  59. # 总页码 > 11
  60. else:
  61. # 当前页如果<=页面上最多显示(11-1)/2个页码
  62. if self.current_page <= self.pager_count_half:
  63. pager_start = 1
  64. pager_end = self.pager_count + 1
  65.  
  66. # 当前页大于5
  67. else:
  68. # 页码翻到最后
  69. if (self.current_page + self.pager_count_half) > self.all_pager:
  70. pager_start = self.all_pager - self.pager_count + 1
  71. pager_end = self.all_pager + 1
  72.  
  73. else:
  74. pager_start = self.current_page - self.pager_count_half
  75. pager_end = self.current_page + self.pager_count_half + 1
  76.  
  77. page_html_list = []
  78. self.params["page"] = 1
  79. first_page = '<li><a href="%s?%s">首页</a></li>' % (self.base_url, self.params.urlencode(),)
  80. page_html_list.append(first_page)
  81.  
  82. if self.current_page <= 1:
  83. prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
  84. else:
  85. self.params["page"] = self.current_page - 1
  86. prev_page = '<li><a href="%s?%s">上一页</a></li>' % (self.base_url, self.params.urlencode(),)
  87.  
  88. page_html_list.append(prev_page)
  89.  
  90. for i in range(pager_start, pager_end):
  91. # self.params : {"page":77,"title":"python","nid":1}
  92.  
  93. self.params["page"] = i # {"page":72,"title":"python","nid":1}
  94. if i == self.current_page:
  95. temp = '<li class="active"><a href="%s?%s">%s</a></li>' % (self.base_url, self.params.urlencode(), i,)
  96. else:
  97. temp = '<li><a href="%s?%s">%s</a></li>' % (self.base_url, self.params.urlencode(), i,)
  98. page_html_list.append(temp)
  99.  
  100. if self.current_page >= self.all_pager:
  101. next_page = '<li class="disabled"><a href="#">下一页</a></li>'
  102. else:
  103. self.params["page"] = self.current_page + 1
  104. next_page = '<li><a href="%s?%s">下一页</a></li>' % (self.base_url, self.params.urlencode(),)
  105. page_html_list.append(next_page)
  106.  
  107. self.params["page"] = self.all_pager
  108. last_page = '<li><a href="%s?%s">尾页</a></li>' % (self.base_url, self.params.urlencode(),)
  109. page_html_list.append(last_page)
  110.  
  111. return ''.join(page_html_list)
  112.  
  113. # class Pagination(object):
  114. #
  115. # def __init__(self, data_num, current_page, url_prefix,params, per_page=10, max_show=4):
  116. # """
  117. # 进行初始化.
  118. # :param data_num: 数据总数
  119. # :param current_page: 当前页
  120. # :param url_prefix: 生成的页码的链接前缀
  121. # :param per_page: 每页显示多少条数据
  122. # :param max_show: 页面最多显示多少个页码
  123. # """
  124. # self.data_num = data_num
  125. # self.per_page = per_page
  126. # self.max_show = max_show
  127. # self.url_prefix = url_prefix
  128. #
  129. # # 把页码数算出来
  130. # self.page_num, more = divmod(data_num, per_page)
  131. # if more:
  132. # self.page_num += 1
  133. #
  134. # try:
  135. # self.current_page = int(current_page)
  136. # except Exception as e:
  137. # self.current_page = 1
  138. # # 如果URL传过来的页码数是负数
  139. # if self.current_page <= 0:
  140. # self.current_page = 1
  141. # # 如果URL传过来的页码数超过了最大页码数
  142. # elif self.current_page > self.page_num:
  143. # self.current_page = self.page_num # 默认展示最后一页
  144. #
  145. # # 页码数的一半 算出来
  146. # self.half_show = max_show // 2
  147. #
  148. # # 页码最左边显示多少
  149. # if self.current_page - self.half_show <= 1:
  150. # self.page_start = 1
  151. # self.page_end = self.max_show
  152. # elif self.current_page + self.half_show >= self.page_num: # 如果右边越界
  153. # self.page_end = self.page_num
  154. # self.page_start = self.page_num - self.max_show
  155. # else:
  156. # self.page_start = self.current_page - self.half_show
  157. # # 页码最右边显示
  158. # self.page_end = self.current_page + self.half_show
  159. #
  160. #
  161. # import copy
  162. # self.params=copy.deepcopy(params) # {"page":"12","title_startwith":"py","id__gt":"5"}
  163. #
  164. #
  165. #
  166. # @property
  167. # def start(self):
  168. # # 数据从哪儿开始切
  169. # return (self.current_page - 1) * self.per_page
  170. #
  171. # @property
  172. # def end(self):
  173. # # 数据切片切到哪儿
  174. # return self.current_page * self.per_page
  175. #
  176. # def page_html(self):
  177. # # 生成页码
  178. # l = []
  179. # # 加一个首页
  180. # l.append('<li><a href="{}?page=1">首页</a></li>'.format(self.url_prefix))
  181. # # 加一个上一页
  182. # if self.current_page == 1:
  183. # l.append('<li class="disabled" ><a href="#">«</a></li>'.format(self.current_page))
  184. # else:
  185. # l.append('<li><a href="{}?page={}">«</a></li>'.format(self.url_prefix, self.current_page - 1))
  186. #
  187. #
  188. #
  189. # # {"page":"12","title_startwith":"py","id__gt":"5"} # "page=12&title_startwith=py&id__gt=5"
  190. #
  191. #
  192. # print(self.params.urlencode())
  193. # for i in range(self.page_start, self.page_end + 1):
  194. # self.params["page"]=i # # {"page":"7","title_startwith":"py","id__gt":"5"} # "page=7&title_startwith=py&id__gt=5"
  195. # if i == self.current_page:
  196. # tmp = '<li class="active"><a href="{0}?page={1}">{1}</a></li>'.format(self.url_prefix, i)
  197. # else:
  198. # tmp = '<li><a href="{0}?{1}">{2}</a></li>'.format(self.url_prefix, self.params.urlencode(),i)
  199. # l.append(tmp)
  200. #
  201. #
  202. #
  203. #
  204. #
  205. #
  206. #
  207. # # 加一个下一页
  208. # if self.current_page == self.page_num:
  209. # l.append('<li class="disabled"><a href="#">»</a></li>'.format(self.current_page))
  210. # else:
  211. # l.append('<li><a href="{}?page={}">»</a></li>'.format(self.url_prefix, self.current_page + 1))
  212. # # 加一个尾页
  213. # l.append('<li><a href="{}?page={}">尾页</a></li>'.format(self.url_prefix, self.page_num))
  214. # return "".join(l)

###############  查看列表页面    ###############

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
  8. <script src="/static/js/jquery-1.12.4.min.js"></script>
  9.  
  10. <style>
  11. .filter a{
  12. text-decoration: none;
  13. color: grey;
  14. }
  15.  
  16. .active{
  17. color: rebeccapurple!important;
  18. }
  19. </style>
  20. </head>
  21. <body>
  22.  
  23. <h4>数据列表</h4>
  24.  
  25. <div class="container">
  26. <div class="row">
  27. <div class="col-md-9">
  28. <a href="{{ add_url }}" class="btn btn-primary">添加数据</a>
  29. {#搜索框,只有配置了search_fields才会展示#}
  30. {% if showlist.config.search_fields %}
  31. {#没有写method,默认是一个get请求#}
  32. <form action="" class="pull-right">
  33. <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>
  34. </form>
  35. {% endif %}
  36.  
  37. {#构建这个表单,就是为了批量操作的,因为需要下面的列表数据,所以包到一起, #}
  38. <form action="" method="post">
  39. {% csrf_token %}
  40. <select name="action" class="form-control" id="" style="width: 200px;margin: 8px 2px;display: inline-block;vertical-align: -1px">
  41. <option value="">---------------</option>
  42. {# get_action_list的结果:[{"name":""patch_init,"desc":"批量初始化"}]#}
  43. {#每一个item就是一个字段,#}
  44. {% for item in showlist.get_action_list %}
  45. <option value="{{ item.name }}">{{ item.desc }}</option>
  46. {% endfor %}
  47.  
  48. </select><button type="submit" class="btn btn-success">Go</button>
  49. <table class="table table-bordered table-striped">
  50. {#表头#}
  51. <thead>
  52. <tr>
  53. {% for item in showlist.get_header %}
  54. <th>{{ item }}</th>
  55. {% endfor %}
  56.  
  57. </tr>
  58.  
  59. </thead>
  60. {#表数据#}
  61. <tbody>
  62. {% for data in showlist.get_body %}
  63.  
  64. <tr>
  65. {% for item in data %}
  66. <td>{{ item }}</td>
  67. {% endfor %}
  68.  
  69. </tr>
  70. {% endfor %}
  71.  
  72. </tbody>
  73. </table>
  74. <nav class="pull-right">
  75. <ul class="pagination">
  76. {{ showlist.pagination.page_html|safe }}
  77. </ul>
  78. </nav>
  79.  
  80. </form>
  81. </div>
  82.  
  83. {#筛选#}
  84. <div class="col-md-3">
  85. {% if showlist.config.list_filter %}
  86. <div class="filter">
  87. <h4 style="">Filter</h4>
  88. {% for filter_field,linktags in showlist.get_filter_linktags.items %}
  89. <div class="well">
  90. <p>By {{ filter_field.upper }}</p>
  91. {% for link in linktags %}
  92. <p>{{ link|safe }}</p>
  93. {% endfor %}
  94. </div>
  95. {% endfor %}
  96.  
  97. </div>
  98. {% endif %}
  99.  
  100. </div>
  101. </div>
  102. </div>
  103.  
  104. <script>
  105.  
  106. $("#choice").click(function () {
  107.  
  108. if($(this).prop("checked")){
  109. $(".choice_item").prop("checked",true)
  110. }else {
  111. $(".choice_item").prop("checked",false)
  112. }
  113.  
  114. })
  115.  
  116. </script>
  117. </body>
  118. </html>

###############  修改页面    ###############

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
  8. <script src="/static/js/jquery-1.12.4.min.js"></script>
  9.  
  10. <style>
  11.  
  12. input,select {
  13. display: block;
  14. width: 100%;
  15. height: 34px;
  16. padding: 6px 12px;
  17. font-size: 14px;
  18. line-height: 1.42857143;
  19. color: #555;
  20. background-color: #fff;
  21. background-image: none;
  22. border: 1px solid #ccc;
  23. border-radius: 4px;
  24. -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
  25. box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
  26. -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
  27. -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
  28. transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
  29. }
  30.  
  31. .error{
  32. color: red;
  33. }
  34.  
  35. </style>
  36. </head>
  37. <body>
  38.  
  39. <h3>编辑页面</h3>
  40.  
  41. {% include 'form.html' %}
  42.  
  43. </body>
  44. </html>

###############  删除页面    ###############

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. </head>
  8. <body>
  9.  
  10. <h3>删除页面</h3>
  11.  
  12. <form action="" method="post">
  13. {% csrf_token %}
  14. <button>确认删除?</button>
  15. <a href="{{ url }}">取消</a>
  16. </form>
  17.  
  18. </body>
  19. </html>

###############  抽象form表单部分    ###############

  1. <div class="container">
  2. <div class="row">
  3. <div class="col-md-6 col-xs-8 col-md-offset-3">
  4. <form action="" method="post" novalidate>
  5. {% csrf_token %}
  6. {% for field in form %}
  7. <div style="position: relative">
  8. <label for="">{{ field.label }}</label>
  9. {{ field }} <span class=" error pull-right">{{ field.errors.0 }}</span>
  10.  
  11. {% if field.is_pop %}
  12. {#如果是一个一对多多对多的字段,需要在字段的右侧放一个加号,需要弹出新的页面,来添加数据#}
  13. {#position,设置标签的位置,父标签是相对定位,子标签是绝对定位,#}
  14. {#你怎么知道一个字段是一对多多对多的字段??,根据字段的类型,如果是一对多,多对多,加一个is_pop的字段为true#}
  15. {#绑定一个点击事件,点击要跳转到一个url,#}
  16. <a onclick="pop('{{ field.url }}')" style="position: absolute;right: -30px;top: 20px"><span style="font-size: 28px">+</span></a>
  17. {% endif %}
  18. </div>
  19. {% endfor %}
  20.  
  21. <button type="submit" class="btn btn-default pull-right">提交</button>
  22. </form>
  23. </div>
  24. </div>
  25. </div>
  26. <script>
  27. function pop(url) {
  28. {#点击之后弹出一个窗口,路径是传入的url,#}
  29. window.open(url,"","width=600,height=400,top=100,left=100")
  30. {#top=100,left=100,控制弹出窗口的位置,大小,#}
  31. }
  32. </script>

###############  新增页面   ###############

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
  8. <script src="/static/js/jquery-1.12.4.min.js"></script>
  9.  
  10. <style>
  11.  
  12. input,select {
  13. display: block;
  14. width: 100%;
  15. height: 34px;
  16. padding: 6px 12px;
  17. font-size: 14px;
  18. line-height: 1.42857143;
  19. color: #555;
  20. background-color: #fff;
  21. background-image: none;
  22. border: 1px solid #ccc;
  23. border-radius: 4px;
  24. -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
  25. box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
  26. -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
  27. -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
  28. transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
  29. }
  30.  
  31. .error{
  32. color: red;
  33. }
  34.  
  35. </style>
  36. </head>
  37. <body>
  38.  
  39. <h3>添加页面</h3>
  40.  
  41. {% include 'form.html' %}
  42.  
  43. <script>
  44. function pop_response (pk,text,id) {
  45. {#添加内容之后,返回的时候能自动带回到页面,#}
  46. console.log(pk,text,id);
  47.  
  48. // 选择哪一个select标签
  49. // option的文本值和value值
  50.  
  51. var $option=$('<option>'); // <option></option>
  52. $option.html(text); // <option>南京出版社</option>
  53. $option.val(pk); // <option value=111>南京出版社</option>
  54. $option.attr("selected","selected") ; // <option value=111>南京出版社</option>
  55. $("#"+id).append($option)
  56.  
  57. }
  58. </script>
  59.  
  60. </body>
  61. </html>

###############  pop页面    ###############

  1. <!DOCTYPE html>
  2. <html lang="zh-CN">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>Title</title>
  6. <meta name="viewport" content="width=device-width, initial-scale=1">
  7. </head>
  8. <body>
  9.  
  10. <script>
  11. {#这个pop_response是自己定义的#}
  12. window.opener.pop_response('{{ res.pk }}',"{{ res.text }}",'{{ res.pop_res_id }}')
  13. window.close()
  14. </script>
  15.  
  16. </body>
  17. </html>

###############  admin    ###############

###############  admin    ###############

crm项目-stark组件的更多相关文章

  1. crm项目-stark组件分析

    ###############    stark组件     ################ """ 这个stark组件是非常神奇的 1,独立的一个组件 2,没有mod ...

  2. day 70 crm(7):stark组件调用,以及权限分配

    前情提要: 复习:  1: orm !!!!! 2: session 3: django 4:  前端在复习 5:  复习中间件 学习的stark 的组件调用,以及权限的应用 一:权限的概念,  1: ...

  3. crm 使用stark组件

    # Create your models here. from django.db import models class Department(models.Model): "" ...

  4. day67 crm(4) stark组件的增删改 以及 model_from使用和from组件回顾

        前情提要:Django  stark 组件开发的 增删改,  model_form组件的使用 form组件的回顾 一:list_display_link  创建 功能描述:   使包含的字段能 ...

  5. crm项目-权限组件

    ###############    表结构分析     ################ """ 表结构设计: 1,四张表 用户表,userinfo,这个表本身不会被创 ...

  6. CRM项目之stark组件

    . stark也是一个app(用startapp stark创建),目标时把这个做成一个可以拔插的组件 . setting文件下INSTALLED_APPS 路径要配置好(app的注册) . 写好si ...

  7. CRM项目之stark组件(2)

    那么从今天开始呢,我们就要开始设计属于我们自己的admin组件,起个名字就叫stark吧(当然你愿意叫什么都可以). stark组件之四步走 仿照admin组件实现流程,stark组件要实现四件事情: ...

  8. crm项目之stark组件前戏(二)

    stark组件的设计主要来源于django中admin的功能,在django admin中只需要将模型表进行注册,就可以在页面对该表进行curd的动作,那么django admin是如何做的呢? 在d ...

  9. CRM项目之RBAC权限组件-day26

    写在前面 上课第26天,打卡: 世间安得双全法 不负如来不负卿 s17day26 CRM项目 项目概要:XX公司CRM - 权限管理,公共组件,app ***** - 熟悉增删改查,Low *** - ...

随机推荐

  1. sonarqube linux安装总结,集成jenkins

    第一条建议,安装sonarqube首先看好版本号,不同版本号的安装配置可能不同,如果你想走捷径,看官网对应发布的安装使用教程.https://www.sonarqube.org/downloads/ ...

  2. Nginx和php交互的两种方式

    Unix socket 也叫IPC socket  也就是进程间通信套接字用于同一台主机上的不同进程间交换数据 TCP socket IP socket要利用主机的传输层(tcp),可以用于同一台主机 ...

  3. UML-UML工具与UML蓝图

    1.UML应用场景 1).UML作为草图 2).UML作为蓝图. UML生成java代码(前向工程) java代码生成UML(逆向工程) 2.如果绘制了UML草图,如何在编码后更新该图形? 逆向工程, ...

  4. 实现3d效果

    transform-origin: center left 60px;可以实现3d转换

  5. 苹果下架2.5万赌博APP!一场净化风暴正在迅速成型

    当下智能手机发展得如火如荼,但对于大众来说,体验终究还是要落到包罗万千的APP上.APP身为智能手机的灵魂,全面渗入了大众的工作.生活.娱乐.学习等多个方面.每一个APP的背后,其实都在打开着一扇通往 ...

  6. vue接口交互写死的

    vue接口 写死的 RoleOfUserOrgRef: function ({ commit }, param) { return new Promise((resolve) => { $axi ...

  7. Spring Cloud服务间调用鉴权

    学习使用Spring Cloud 微服务间的调用都是RestFul风格,如何保证调用之间的安全性,这是一个很重要的问题. 通过查阅资料http://wiselyman.iteye.com/blog/2 ...

  8. UML-交互图包含哪些图?

    猫比狗精明,但你无法让8只猫在雪地里拉雪橇---杰夫.瓦尔德斯 本章是重点. 1.总览 2.顺序图 1).类A具有doOne方法和类B的属性 2).doOne方法中调用类B的doTwo()和doThr ...

  9. HDU 1257最少拦截系统[动态规划]

    传送门:http://acm.hdu.edu.cn/showproblem.php?pid=1257                                                 最 ...

  10. nm命令介绍

    一.参考文章 网址1:https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/nm.html 参考2: man nm 参考3:<linux ...