############### 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;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=" 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; 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; 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 ###############