##更新内容
#1、list_display_links #2、form与modelform #3、bulk_create批量插入数据 #4、封装展示类: #5、使用分页器
#6、自动保存搜索条件,即保存url地址状态
##list_display_links

#1、实现给相应的字段添加a标签,连接功能,点击可以跳转、 def list_view(self, request): #查看self.model <class 'app01.models.Book'> 那张表查看就代表谁 # print(self.model) queryset = self.model.objects.all() # 表头展示 header_list = [] for field_or_func in self.get_new_list(): if isinstance(field_or_func,str): if field_or_func == '__str__': #当用户没有指定list_display 默认展示当前表的大写名字 val = self.model._meta.model_name.upper() else: val = self.model._meta.get_field(field_or_func).verbose_name else: val = field_or_func(self,is_header=True) header_list.append(val) #表单展示 body_list = [] #格式定义 [[obj1.title,obj1.price],[obj2.title,obj2.price],[]] for obj in queryset: tmp = [] for field_or_func in self.get_new_list():#注意这里的list_display查找顺序,先查自己的,在查全局的,然后循环要展示的字段 if isinstance(field_or_func,str): val = getattr(obj,field_or_func) #通过反射获取obj对象中field字段所对应的值 if field_or_func in self.list_display_links: _url = self.get_reverse_url('edit',obj) val = mark_safe('<a href="%s">%s</a>'%(_url,val)) else: val = field_or_func(self,obj=obj) tmp.append(val) body_list.append(tmp) return render(request,'stark/list_view.html',locals()) #2、当表中存在a标签链接后删除默认的编辑功能字段 def get_new_list(self): tmp=[] tmp.append(ModelStark.check_box) tmp.extend(self.list_display) if not self.list_display_links: tmp.append(ModelStark.edit_col) tmp.append(ModelStark.delete_col) return tmp
##form与modelform
模型表的增删改查 form组件 1.校验数据 2.渲染标签 3.展示信息 modelform用法 class StudentList(ModelForm): class Meta: model =Student #对应的Model中的类 fields = "__all__" #字段,如果是__all__,就是表示列出所有的字段 exclude = None #排除的字段 #error_messages用法: error_messages = { 'name':{'required':"用户名不能为空",}, 'age':{'required':"年龄不能为空",}, } #widgets用法,比如把输入用户名的input框给为Textarea #首先得导入模块 from django.forms import widgets as wid #因为重名,所以起个别名 widgets = { "name":wid.Textarea(attrs={"class":"c1"}) #还可以自定义属性 } #labels,自定义在前端显示的名字 labels= { "name":"用户名" }
##modelform实现增删改查

#1、modelform的前端渲染跟forms组件一模一样实现增删改查 自定义配置类:C:starkproapp01stark.py class BookConfig(ModelStark): list_display = ['title','price','publishDate','publish'] list_display_links = ['title','price'] class BookModelForm(ModelForm): class Meta: model = models.Book fields = '__all__' from django.forms import widgets as wid widgets = { 'title':wid.TextInput(attrs={'class':'form-control'}), 'price':wid.TextInput(attrs={'class':'form-control'}), 'publishDate':wid.DateInput(attrs={'class':'form-control'}), 'publish':wid.Select(attrs={'class':'form-control'}), 'authors':wid.SelectMultiple(attrs={'class':'form-control'}) } model_form_class = BookModelForm 默认配置类:C:starkprostarkservicestark.py class ModelStark(object): #ModelStark中时默认的参数,用户自定义的的在C:starkproapp01stark.py list_display = ['__str__',] list_display_links = [] model_form_class = None def list_view(self, request): #给前端(展示列表list_view)传一个反向解析出来的url,作为跳转使用 url = self.get_reverse_url('add') ##默认定义一个model_form_class,如果自定义配置类在C:starkproapp01stark.py 中配置了,就使用用户自定义的 def get_model_form(self): if self.model_form_class: return self.model_form_class from django.forms import ModelForm class ModelFormClass(ModelForm): class Meta: model = self.model fields = '__all__' return ModelFormClass def add_view(self, request): model_form_class = self.get_model_form() model_form_obj = model_form_class() if request.method == 'POST': model_form_obj = self.model_form_class(request.POST) if model_form_obj.is_valid(): model_form_obj.save() return redirect(self.get_reverse_url('list')) return render(request, 'stark/add_view.html', locals()) def edit_view(self, request, id): edit_obj = self.model.objects.filter(pk=id).first() model_form_class = self.get_model_form() model_form_obj =model_form_class(instance=edit_obj) if request.method == 'POST': model_form_obj = model_form_class(request.POST,instance=edit_obj) if model_form_obj.is_valid(): model_form_obj.save() return redirect(self.get_reverse_url('list')) return render(request,'stark/edit_view.html',locals()) def delete_view(self, request, id): self.model.objects.filter(pk=id).delete() return redirect(self.get_reverse_url('list')) #2、在后端代码更加精简 母版:base.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link rel="stylesheet" href="/static/bs-3.3.7/css/bootstrap.css"> <script src="/static/bs-3.3.7/js/bootstrap.min.js"></script> <style> input[name],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; } </style> </head> <body> <div class="container"> <div class="row"> {% block content %} {% endblock %} </div> </div> </body> </html> 子板:增加页面 add_view.html {% extends 'stark/base.html' %} {% block content %} <div class="col-md-6 col-md-offset-3"> <h2 class="text-center">添加数据</h2> <form action="" method="post"> {% csrf_token %} {% for form_obj in model_form_obj %} <p>{{ form_obj.label }}{{ form_obj }} <span>{{ form_obj.error.0 }}</span> </p> {% endfor %} <input type="submit" class="btn btn-success pull-right"> </form> </div> {% endblock %} 子板:编辑页面 edit_view.html {% extends 'stark/base.html' %} {% block content %} <div class="col-md-6 col-md-offset-3"> <h2 class="text-center">添加数据</h2> <form action="" method="post"> {% csrf_token %} {% for form_obj in model_form_obj %} <p>{{ form_obj.label }}{{ form_obj }} <span>{{ form_obj.error.0 }}</span> </p> {% endfor %} <input type="submit" class="btn btn-success pull-right"> </form> </div> {% endblock %}
##bulk_create批量插入数据
# for i in range(1000): # models.Publish.objects.create(name='%s出版社'%i) # obj_list = [] # for i in range(10000): # obj_list.append(models.Publish(name='出版社%s'%i)) # models.Publish.objects.bulk_create(obj_list)
##自动保存搜索条件
#1、核心代码: import copy params = copy.deepcopy(request.GET) #request字典是不能修改的,get请求后端获取到的数据格式如:use=owen&pwd=111 想要修改的话直通通过深拷贝方式 params['xxx'] = 123 #然后可以进行修改 print(params) print(params.urlencode()) # 将字典变成urlencoded数据格式,就能拿到数据格式为:use=owen&pwd=111 return render(request,'publish.html',locals()) #2、分页器使用: queryset = models.Publish.objects.all() page_obj = Pagination(request.GET.get('page',1),queryset.count(),request)#给分页器传入request page_queryset = queryset[page_obj.start:page_obj.end]
##封装展示类

#1、展示类 class ShowList:#注意self的区别 def __init__(self,config_obj,queryset): self.config_obj = config_obj #对应每一个配置类对象 self.queryset = queryset def get_header(self): # 表头展示 header_list = [] for field_or_func in self.config_obj.get_new_list(): if isinstance(field_or_func, str): if field_or_func == '__str__': # 当用户没有指定list_display 默认展示当前表的大写名字 val = self.config_obj.model._meta.model_name.upper() else: val = self.config_obj.model._meta.get_field(field_or_func).verbose_name else: val = field_or_func(self, is_header=True) header_list.append(val) return header_list def get_body(self): # 表单展示 body_list = [] # 格式定义 [[obj1.title,obj1.price],[obj2.title,obj2.price],[]] for obj in self.queryset: tmp = [] for field_or_func in self.config_obj.get_new_list(): # 注意这里的list_display查找顺序,先查自己的,在查全局的,然后循环要展示的字段 if isinstance(field_or_func, str): val = getattr(obj, field_or_func) # 通过反射获取obj对象中field字段所对应的值 if field_or_func in self.config_obj.list_display_links: _url = self.config_obj.get_reverse_url('edit', obj) val = mark_safe('<a href="%s">%s</a>' % (_url, val)) else: val = field_or_func(self.config_obj, obj=obj) tmp.append(val) body_list.append(tmp) return body_list #2、默认配置类 class ModelStark(object): def list_view(self, request): #查看self.model <class 'app01.models.Book'> 那张表查看就代表谁 # print(self.model) queryset = self.model.objects.all() show_obj = ShowList(self,queryset)#传self :为展示类对象 url = self.get_reverse_url('add') return render(request,'stark/list_view.html',locals()) #3、前端 </tbody> {% extends 'stark/base.html' %} {% block content %} <h2 class="text-center">数据展示</h2> <div class="col-md-8 col-md-offset-2"> <a href="{{ url }}" class="btn btn-primary">添加数据</a> <table class="table table-striped table-bordered table-hover"> <thead> <tr> {% for foo in show_obj.get_header %} <td>{{ foo }}</td> {% endfor %} </tr> </thead> <tbody> {% for body in show_obj.get_body %} <tr> {% for foo in body %} <td> {{ foo }} </td> {% endfor %} </tr> {% endfor %} </tbody> </table> </div> {% endblock %}
##使用分页器

class Pagination(object): def __init__(self, current_page, all_count,request, per_page_num=10, pager_count=11):#添加request参数 """ 封装分页相关数据 :param current_page: 当前页 :param all_count: 数据库中的数据总条数 :param per_page_num: 每页显示的数据条数 :param pager_count: 最多显示的页码个数 用法: queryset = model.objects.all() page_obj = Pagination(current_page,all_count) page_data = queryset[page_obj.start:page_obj.end] 获取数据用page_data而不再使用原始的queryset 获取前端分页样式用page_obj.page_html """ 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 # 总页码 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 self.params = copy.deepcopy(request.GET) #对传入的request参数进行 深拷贝 @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/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_end = self.all_pager + 1 pager_start = self.all_pager - self.pager_count + 1 else: pager_start = self.current_page - self.pager_count_half pager_end = self.current_page + self.pager_count_half + 1 page_html_list = [] # 添加前面的nav和ul标签 page_html_list.append(''' <nav aria-label='Page navigation>' <ul class='pagination'> ''') first_page = '<li><a href="?page=%s">首页</a></li>' % (1) page_html_list.append(first_page) if self.current_page <= 1: prev_page = '<li class="disabled"><a href="#">上一页</a></li>' else: prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,) page_html_list.append(prev_page) for i in range(pager_start, pager_end): self.params['page'] = i #实现动态变化页码 if i == self.current_page: temp = '<li class="active"><a href="?%s">%s</a></li>' % (self.params.urlencode(), i,) else: temp = '<li><a href="?%s">%s</a></li>' % (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: next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,) page_html_list.append(next_page) last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,) page_html_list.append(last_page) # 尾部添加标签 page_html_list.append(''' </nav> </ul> ''') return ''.join(page_html_list)

#1、展示类 class ShowList: def __init__(self,config_obj,queryset,request): self.config_obj = config_obj self.queryset = queryset self.request = request current_page = self.request.GET.get('page',1) self.page_obj = Pagination(current_page=current_page,all_count=self.queryset.count(),request=self.request) self.page_queryset = self.queryset[self.page_obj.start:self.page_obj.end] def get_body(self): # 表单展示 body_list = [] # 格式定义 [[obj1.title,obj1.price],[obj2.title,obj2.price],[]] for obj in self.page_queryset:#使用分页器 tmp = [] for field_or_func in self.config_obj.get_new_list(): # 注意这里的list_display查找顺序,先查自己的,在查全局的,然后循环要展示的字段 if isinstance(field_or_func, str): val = getattr(obj, field_or_func) # 通过反射获取obj对象中field字段所对应的值 if field_or_func in self.config_obj.list_display_links: _url = self.config_obj.get_reverse_url('edit', obj) val = mark_safe('<a href="%s">%s</a>' % (_url, val)) else: val = field_or_func(self.config_obj, obj=obj) tmp.append(val) body_list.append(tmp) return body_list #2、默认配置类 class ModelStark(object): def list_view(self, request): #查看self.model <class 'app01.models.Book'> 那张表查看就代表谁 # print(self.model) queryset = self.model.objects.all() show_obj = ShowList(self,queryset,request)#创建展示类对象,给展示类传递一个request url = self.get_reverse_url('add') return render(request,'stark/list_view.html',locals()) #3、前端 {{ show_obj.page_obj.page_html|safe }}