优化代码
1:页面的增删改查url反转的封装到类里:ModelSatrk
# 编辑页面的url def get_edit_url(self,obj): edit_url = reverse("%s_%s_change" % self.app_model_name,args=(obj.pk,)) return edit_url # 删除页面url def get_delete_url(self,obj): del_url = reverse("%s_%s_delete" % self.app_model_name,args=(obj.pk,)) return del_url def get_add_url(self,obj): add_url = reverse("%s_%s_delete" % self.app_model_name,args=(obj.pk,)) return add_url def get_list_url(self,obj): list_url = reverse("%s_%s_delete" % self.app_model_name,args=(obj.pk,)) return list_url
2:显示页面的编辑和删除按钮
# 编辑按钮 def edit(self,obj=None,is_header=False): if is_header: return "操作" return mark_safe("<a href='%s'>编辑</a>"%self.get_edit_url(obj)) # return 的url需要反向解析,需要取到name的值 # 删除按钮 def delete(self,obj=None,is_header=False): if is_header: return "操作" # 如何反向解析url return mark_safe("<a href='%s'>删除</a>"%self.get_delete_url(obj))
增删改查页面
# 使用modelform 处理的基本流程 添加页面: get请求: form=UserModelForm()------>渲染表单标签 post请求: form=UserModelForm(data=request.POST) if form.is_valid(): form.save()-------->create一条记录 编辑页面: get请求: edit_obj=User.objects.filter(pk=id).first() form=UserModelForm(instance=edit_obj)------>渲染表单标签 post请求: edit_obj=User.objects.filter(pk=id).first() form=UserModelForm(data=request.POST,instance=edit_obj) if form.is_valid(): form.save()-------->对edit_obj的数据更新为request.POST
增
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <h3>添加数据</h3> <form action="" method="post" novalidate> {% csrf_token %} {{ form.as_p }} <input type="submit" value="submit"> </form> </body> </html>
需要后端展示页面传值
add_url=self.get_add_url()
增的页面表单第二种渲染方式
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css"> <style> .form-group .input_style input { 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> {# 第一种渲染表单方式 #} {#<form action="" method="post" novalidate>#} {# {% csrf_token %}#} {# {{ form.as_p }}#} {# <input type="submit" value="submit">#} {#</form>#} {# 第三种渲染表单方式 #} <div class="container"> <div class="row"> <div class="col-md-6"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="">{{ field.label }}</label> <div class="input_style"> {{ field }} <span class="error pull-right">{{ field.errors.0 }}</span> </div> </div> {% endfor %} <p><input type="submit" class="btn btn-default " value="提交"></p> </form> </div> </div> </div> </body> </html>
关于显示错误信息
1:用户定制了(显示中文的)
2:用户没有定义(显示英文)
需要添加 model_form_class=None 变量来判断当前用户有没有定义信息
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
from django.utils.safestring import mark_safe from django.urls import reverse from django.forms import ModelForm # class BookModelForm(ModelForm): class Meta: model=Book fields='__all__' # 展示字段 error_messages={ # 针对book表的error_messages "title":{"required":"不能为空"}, "price":{"required":"不能为空"}, } class BookConfig(ModelSatrk): list_display = ["id","title","price",] # z这个list_display只针对Book表 model_form_class=BookModelForm # 当用户定制显示信息,就自己定制的,没有用默认 # 自制注册功能(admin表的注册 site.register(Book,BookConfig)
# 添加页面视图 def add_view(self,request): # 基于modelform # 先走用户的(如果用户写了这个名字,就用用户的) 如果为空既是用户没有定制显示信息 if not self.model_form_class: # 用父类 ModelFormClass=self.get_modelform_class() else: # 用户定义了 ModelFormClass=self.model_form_class if request.method=="GET": form=ModelFormClass() # 取到当前表数据(渲染表单表单) return render(request,"stark/add_view.html",{"form":form}) else: form=ModelFormClass(data=request.POST) if form.is_valid(): # is_valid 判断当前数据通不通过 form.save() # 新建一条数据 return redirect(self.get_list_url()) else: # 数据有问题 return render(request, "stark/add_view.html", {"form":form})
优化(这部分代码在下面重复调用较多)
if not self.model_form_class: # 用父类 ModelFormClass=self.get_modelform_class() else: # 用户定义了 ModelFormClass=self.model_form_class
把他封装到类里面
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
# 添加页面视图 def add_view(self,request): # 基于modelform ModelFormClass=self.model_form_class if request.method=="GET": form=ModelFormClass() # 取到当前表数据(渲染表单表单) return render(request,"stark/add_view.html",{"form":form}) else: form=ModelFormClass(data=request.POST) if form.is_valid(): # is_valid 判断当前数据通不通过 form.save() # 新建一条数据 return redirect(self.get_list_url()) else: # 数据有问题 return render(request, "stark/add_view.html", {"form":form}) # 编辑视图 def change_view(self,request,id): edit_book = self.model.objects.filter(pk=id).first() # 取到要修改的数据对象 ModelFormClass = self.model_form_class form = ModelFormClass(instance=edit_book) # 需要编辑的内容 if request.method=="GET": form=ModelFormClass(instance=edit_book) return render(request,"stark/change_view.html",{"form":form}) else: form=ModelFormClass(data=request.POST,instance=edit_book) if form.is_valid(): form.save() return redirect("/index/") return render(request,"stark/change_view.html",{"form":form})
优化二:添加页面和编辑页面基本相同 利用
include
相同部分放到一个form.html里面
<div class="container"> <div class="row"> <div class="col-md-6"> <form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="">{{ field.label }}</label> <div class="input_style"> {{ field }} <span class="error pull-right">{{ field.errors.0 }}</span> </div> </div> {% endfor %} <p><input type="submit" class="btn btn-default " value="提交"></p> </form> </div> </div> </div>
调用
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css"> <style> .form-group .input_style input { 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> {# 第一种渲染表单方式 #} {#<form action="" method="post" novalidate>#} {# {% csrf_token %}#} {# {{ form.as_p }}#} {# <input type="submit" value="submit">#} {#</form>#} {# 第三种渲染表单方式 #} {% include 'stark/form.html' %} </body> </html>
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css"> <style> .form-group .input_style input { 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> {# 第一种渲染表单方式 #} {#<form action="" method="post" novalidate>#} {# {% csrf_token %}#} {# {{ form.as_p }}#} {# <input type="submit" value="submit">#} {#</form>#} {# 第三种渲染表单方式 #} {% include 'stark/form.html' %} </body> </html>
需求:将指定字段名变成有链接-----list_display_links
问题:分为2中情况,1:当有用户定义,用用户的 2、当用户没有定义,就用默认的
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
# 3 完成注册 from stark.service.site import site,ModelSatrk from .models import * from django.utils.safestring import mark_safe from django.urls import reverse from django.forms import ModelForm # class BookModelForm(ModelForm): class Meta: model=Book fields='__all__' # 展示字段 error_messages={ # 针对book表的error_messages "title":{"required":"不能为空"}, "price":{"required":"不能为空"}, } # list_display只针对Book表 class BookConfig(ModelSatrk): list_display = ["id","title","price",] # 用户用于页面显示的字段 model_form_class=BookModelForm # 当用户定制显示错误信息,就自己定制的,没有用默认 list_display_links = ["title"] # 用户用于定制添加跳转编辑页面字段 # 自制注册功能(admin表的注册 site.register(Book,BookConfig)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
# 展示数据 def show_list_view(self,request): print("self.model",self.model) # 打印当前表 # 生成表表头 header_list=[] for field in self.get_list_display(): # ["id","title","price","edit"] if callable(field): # header_list.append(field.__name__) val = field(self,is_header=True) # 定义了一个is_header=True变量 header_list.append(val) else: if field=="__str__": # 默认样式 header_list.append(self.model._meta.model_name.upper()) else: field_obj=self.model._meta.get_field(field) header_list.append(field_obj.verbose_name) # verbose_name 显示描述字段 # 生成表单部分 # header_list:["ID","标题","价格","操作"] data_list = self.model.objects.all() # 去数据库取来的所有数据 对象 print("self.list_display",self.list_display) # 用户定义了self.list_display ['id', 'title', 'price'] # 用户没有定义self.list_display[] # 做成下面我们想要的数据格式 new_data_list=[] # 渲染页面的数据 for obj in data_list: # obj:当前每本书的对象 temp=[] # 当用户定义了list_display的情况 利用反射求值 for field in self.get_list_display(): # ['id', 'title', 'price',delete,edit] , if callable(field): # 当遇到delete,edit函数 val=field(self,obj) # 执行函数返回的返回值 else: # 'id', 'title', 'price' val=getattr(obj,field) # 利用反射getattr取值 当用户没定义list_display用“__str__” # 选择指定字段添加a标签跳转到edit页面 if field in self.list_display_links: val=mark_safe("<a href='%s'>%s</a>"%(self.get_edit_url(obj),val)) temp.append(val) # 当走默认的话,也会把__str__传到val new_data_list.append(temp) print(new_data_list) # [[1, '《看见》---柴静', Decimal('12.00')], [2, '《围城》---钱钟书', Decimal('12.00')]] # 添加新的标签: # [ # [1, '《看见》---柴静', Decimal('12.00'), "<a href='/stark/app01/book/3/change/'>编辑</a>", "<a href='/stark/app01/book/3/delete/'>删除</a>"], # [2, '《围城》---钱钟书', Decimal('12.00'), "<a href='/stark/app01/book/3/change/'>编辑</a>", "<a href='/stark/app01/book/3/delete/'>删除</a>"] # ] # ''' # [ # [1,"xxx"], # [2,"xxxxx"], # [3,"xxxxxxx'], # ] # ''' add_url=self.get_add_url() return render(request,"stark/show_list.html",locals())
需求2:当用户指定了添加跳转编辑页面的字段时,将不显示操作的编辑
思路:找到哪里显示了编辑按钮
只需要修改下面逻辑
删
需要跳转到让用户选择肯定或取消
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>删除页面</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css"> </head> <body> {# 将要删除的数据取出来 #} <div> <p>{{ del_obj }}</p></div> <form action="" method="post"> {% csrf_token %} <input type="submit" class="btn btn-danger" value="确认删除吗?"> <a href="{{ list_url }}" class="btn btn-info">取消</a> </form> </body> </html>
# 删除视图 def del_view(self,request,id): # 先取到要删除的对象、 del_obj = self.model.objects.filter(pk=id).first() if request.method=="GET": list_url = self.get_list_url() return render(request,"stark/del_view.html",{"del_obj":del_obj , "list_url":list_url}) else: del_obj.delete() # 将需要删除的对象删除 return redirect(self.get_list_url()) # 跳转回显示页面
接下来需要添加的功能
查看页面: --- 分页器 search action fliter