1、效果图
增
删除
改
2、详细步骤解析
1、构造增删改查url,反向解析
2、ModelForm定制add、edit页面
3、starak中的ModelForm
3、总结、代码
1、知识点
1.解决代码重用
{% include 'form.html' %}
2.自定制配置modelform
每张表,就可自定义配置 labels , widges...
class BookModelForm(ModelForm): class Meta: model = Book fields = "__all__" labels = { "title": '书籍名称', "price": '价格', } ... modelform_class = BookModelForm
3、stark中的Modelform配置
modelform_class = [] # ModelForm组件渲染 list、增、删、改页面 def get_modelform_class(self): """ModelForm组件""" if not self.modelform_class: from django.forms import ModelForm class ModelFormDemo(ModelForm): class Meta: model = self.model fields = "__all__" return ModelFormDemo else: return self.modelform_class
配置样式,由于不确定字段,得在前端玩!
4.change_view()
注意 instance,否则为添加 form = ModelFormDemo(request.POST, instance=edit_obj) if form.is_valid(): form.save()
2、模板层代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> {% block title %} <title>Title</title> {% endblock %} <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css"> <script src="/static/jQuery/jquery-3.2.1.min.js"></script> {% block css %} {% endblock %} </head> <body> <div class="container"> <div class="row"> {% block header %} {% endblock %} <div class="col-md-9 col-md-offset-1"> {% block content %} {% endblock %} </div> </div> </div> {% block javascript %} {% endblock %} </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
{% extends 'base.html' %} {% block title %} <title>add页面</title> {% endblock %} {% block css %} <style type="text/css"> input,select { display: block; width: 100%; height: 34px; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; color: #555; background-color: #fff; background-image: none; border: 1px solid #ccc; border-radius: 4px; -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075); -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; } .error{ color: red; } </style> {% endblock %} {% block header %} <h3>add页面</h3> {% endblock %} {% block content %} {% include 'form.html' %} {% endblock %}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
{% extends 'add_view.html' %} {% block title %} <title>edit页面</title> {% endblock %} {% block header %} <h3>edit页面</h3> {% endblock %}
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>删除页面</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css"> <script src="/static/jQuery/jquery-3.2.1.min.js"></script> </head> <body> <div class="container"> <form action="" method="post" class="text-center"> {% csrf_token %} <p class="text-info">你确认要删除这条记录?</p> <button class="btn btn-danger">确认</button> <a href="{{ url }}" class="btn btn-primary">取消</a> </form> </div> </body> </html>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
<form action="" method="post" novalidate> {% for field in form %} {% csrf_token %} <div class="form-group"> <label for="">{{ field.label }}</label> {{ field }} <span class="error pull-right">{{ field.errors.0 }}</span> </div> {% endfor %} <br> <button class="btn btn-success pull-right">提交</button> </form>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
{% extends 'base.html' %} {% block title %} <title>list页面</title> {% endblock %} {% block header %} <h3>list页面</h3> {% endblock %} {% block content %} <a class="btn btn-primary" href="{{ add_url }}">添加数据</a> <table class="table table-bordered table-striped"> <tr> {% for header in header_list %} <th>{{ header }}</th> {% endfor %} </tr> {% for data in new_data_list %} <tr> {% for item in data %} <td>{{ item }}</td> {% endfor %} </tr> {% endfor %} </table> {% endblock %} {% block javascript %} <script type="text/javascript"> $('#choice').click(function () { if ($(this).prop('checked')) { //对象自身属性中是否具有指定的属性 $('.choice_item').prop("checked", true) } else { $('.choice_item').prop("checked", false) } }) </script> {% endblock %}
3、stark/service/stark.py
from django.conf.urls import url from django.shortcuts import HttpResponse,render,redirect from django.utils.safestring import mark_safe from django.urls import reverse class ModelStark(object): list_display = ["__str__"] # 子类中没有,直接用父类自己的 list_display_links = [] modelform_class = [] def __init__(self,model, site): self.model = model self.site = site # 增删改查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 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'>") def edit(self,obj=None, header=False): if header: return "操作" # 方案1:固定url # return mark_safe("<a href=/stark/app01/userinfo/%s/change>编辑</a>") # 方案2:拼接url # return mark_safe("<a href='%s/change'>编辑</a>") # 方案3:反向解析 model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change"%(app_label,model_name),args=(obj.pk,)) # print("_url",_url) return mark_safe("<a href='%s'>编辑</a>"%_url) def deletes(self,obj=None, header=False): if header: return "操作" 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 mark_safe("<a href='%s'>删除</a>"%_url) # ModelForm组件渲染 list、增、删、改页面 def get_modelform_class(self): """ModelForm组件""" if not self.modelform_class: from django.forms import ModelForm class ModelFormDemo(ModelForm): class Meta: model = self.model fields = "__all__" return ModelFormDemo else: return self.modelform_class def new_list_play(self): """构建 ['checkbox','pk', 'name', 'age', edit,'delete']""" 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 list_view(self, request): print(self.model) # <class 'app01.models.Book'> 用户访问的模型表 # 构建表头 header_list = [] # # header_list = ['选择','pk',...'操作','操作'] for field in self.new_list_play(): if callable(field): # header_list.append(field.__name__) val = field(self,header=True) header_list.append(val) else: if field == "__str__": header_list.append(self.model._meta.model_name.upper()) else: val = self.model._meta.get_field(field).verbose_name # 中文名称 header_list.append(val) # 构建表单 data_list = self.model.objects.all() # [obj1,obj2,...] new_data_list = [] for obj in data_list: # Book表模型,Author表模型 temp = [] for field in self.new_list_play(): # ['name','age'] if callable(field): # edit() 可调用的 val = field(self,obj) # 直接调用edit()函数 print('val--------->',val) else: val = getattr(obj,field) # 反射 obj是实例对象,name是方法 # list_display_links 按钮 if field in self.list_display_links: model_name = self.model._meta.model_name app_label = self.model._meta.app_label _url = reverse("%s_%s_change" % (app_label, model_name), args=(obj.pk,)) # print(_url) val = mark_safe("<a href='%s'>%s</a>"%(_url,field)) temp.append(val) new_data_list.append(temp) print('new_data_list',new_data_list) # 构造数据 [['jack', 44], ['mark', 33]] # 构建一个addurl add_url = self.get_add_url() return render(request,'list_view.html', locals()) def add_view(self, request): ModelFormDemo=self.get_modelform_class() form = ModelFormDemo() if request.method == "POST": form = ModelFormDemo(request.POST) if form.is_valid(): form.save() return redirect(self.get_list_url()) return render(request, "add_view.html",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): edit_obj = self.model.objects.filter(pk=id).first() ModelFormDemo=self.get_modelform_class() form = ModelFormDemo(instance=edit_obj) if request.method == "POST": form = ModelFormDemo(request.POST,instance=edit_obj) if form.is_valid(): form.save() return redirect(self.get_list_url()) return render(request, "change_view.html",locals()) def get_urls2(self): """构造 add/delete/change""" model_name = self.model._meta.model_name app_label = self.model._meta.app_label temp = [] temp.append(url(r'^$', self.list_view, name='%s_%s_list'%(app_label,model_name))) temp.append(url(r'^add/', self.add_view, name='%s_%s_add'%(app_label,model_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))) return temp @property def urls2(self): return self.get_urls2(), None, None class StarkSite(object): """site单例类""" 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) def get_urls(self): """构造一层urls app01/book""" temp = [] for model, stark_class_obj in self._registry.items(): print(model, 'stark_clas_obj', stark_class_obj) # 不同的model模型表 """ <class 'app01.models.UserInfo'> ----> <app01.starkadmin.UserConfig object at 0x00000072DDB65198> <class 'app01.models.Book'> ----> <stark.service.stark.ModelStark object at 0x00000072DDB65240> """ app_label = model._meta.app_label # app01 model_name = model._meta.model_name # book # temp.append(url(r'^%s/%s'%(app_label, model_name),([],None,None))) temp.append(url(r'^%s/%s/'%(app_label, model_name),stark_class_obj.urls2)) """ path('app01/userinfo/',UserConfig(Userinfo,site).urls2), path('app01/book/',ModelStark(Book,site).urls2), """ return temp @property def urls(self): # return [],None,None return self.get_urls(),None,None site = StarkSite() # 单例对象
4、app01下的stark.py
from stark.service import stark from .models import * from django.forms import ModelForm class BookModelForm(ModelForm): class Meta: model = Book fields = "__all__" labels = { "authors":"作者", "publishDate":"出版日期", } class BookConfig(stark.ModelStark): list_display = ['nid', 'title', 'price'] modelform_class = BookModelForm class AuthorConfig(stark.ModelStark): list_display = ['nid', 'name', 'age'] list_display_links = ['name','age'] stark.site.register(Book,BookConfig) stark.site.register(Publish) stark.site.register(Author,AuthorConfig) stark.site.register(AuthorDetail) print(stark.site._registry) """ {<class 'app01.models.Book'>: <stark.service.stark.ModelStark object at 0x0000003AA7439630>, <class 'app01.models.Publish'>: <stark.service.stark.ModelStark object at 0x0000003AA7439668>, <class 'app01.models.Author'>: <stark.service.stark.ModelStark object at 0x0000003AA74396A0>, <class 'app01.models.AuthorDetail'>: <stark.service.stark.ModelStark object at 0x0000003AA7439940>} """
附上核心代码注释:
增加页面(利用modelForm):
#1.首先定义一个方法,如果modelForm是自定制的话,就可以去用户自定制的 def get_modelform_class(self): if not self.modelform_class: #如果不是自定制的话,那么就使用默认的。 class ModelFormDemo(ModelForm): class Meta: model = self.model fields = "__all__" return ModelFormDemo else: return self.modelform_class #不论是哪个都需要返回。
2.admin中自定制:
class ModelFormDemo(ModelForm): class Meta: model = Book fields = "__all__" labels = { "title": "书籍名称", "price": "价格" } class BookConfig(ModelStark): list_display = ["title","price","publishDate"] modelform_class = ModelFormDemo
3. 增加的函数:
def add_view(self,request): ModelFormDemo=self.get_modelform_class() #取到ModelFormDemo if request.method=="POST": form = ModelFormDemo(request.POST) if form.is_valid(): form.save() #如果是POST请求表示添加,从request.POST取到数据,直接添加即可。 return redirect(self.get_list_url()) else: #字段填写错误,在前端利用{{form.errors.0}}显示出来。页面不会刷新。 return render(request, "add_view.html", locals()) } form = ModelFormDemo() return render(request,"add_view.html",locals())
4.编辑页面
#和增加同理,只是利用ID找到这条数据对象,加一个instarce=数据对象,即可改为更新操作。而不是增加 def change_view(self,request,id): ModelFormDemo = self.get_modelform_class() edit_obj = self.model.objects.filter(pk=id).first() if request.method=="POST": form = ModelFormDemo(request.POST,instance=edit_obj) if form.is_valid(): form.save() return redirect(self.get_list_url()) else: return render(request, "add_view.html", locals()) form = ModelFormDemo(instance=edit_obj) return render(request,"change_view.html",locals())
5.删除页面:
#首先点击按钮后是跳转到一个确认页面,发的是post请求表示确认删除,如果点击a标签的取消表示返回到原来页面。 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())