我们在前一章里列出了整个Xadmin的框架,在这一章里我们先讲两个视图——增、改。
因为增和改差不多,内容都是一样的,只不过改的视图多了个id。我们一步步来实现。因为整个框架是基于上一张的那个Xadmin文件,那么这里就主要讲视图函数
添加数据是用了Django的Form控件自动生成的input标签
默认效果
先放出来代码,再来分析,这里放的是一部分ConfXadmin类的代码
1 class ConfXadmin(object): 2 3 modelform_class = None 4 5 def __init__(self,model,site): 6 self.model = model 7 self.model_name = self.model._meta.model_name 8 self.app_name = self.model._meta.app_label 9 @property 10 def urls2(self): 11 return self.get_urls2(),None,None 12 13 def get_urls2(self): 14 temp = [] 15 #通过name设置反向解析 16 temp.append(url(r'^$',self.list_view,name='{}_{}_list'.format(self.app_name,self.model_name))) 17 temp.append(url(r'^add/$',self.add_view,name='{}_{}_add'.format(self.app_name,self.model_name))) 18 temp.append(url(r'^(d+)/change/$',self.change_view,name='{}_{}_change'.format(self.app_name,self.model_name))) 19 temp.append(url(r'^(d+)/delete/$',self.delete_view,name='{}_{}_delete'.format(self.app_name,self.model_name))) 20 return temp 21 22 23 def get_list_url(self): 24 model_name = self.model._meta.model_name 25 app_label = self.model._meta.app_label 26 27 _url = reverse("%s_%s_list"%(app_label, model_name)) 28 return _url 29 30 def get_modelform_class(self): 31 if not self.modelform_class: 32 from django.forms import ModelForm 33 34 class ModelFormDemo(ModelForm): 35 class Meta: 36 model = self.model 37 fields = '__all__' 38 39 return ModelFormDemo 40 else: 41 return self.modelform_class 42 43 def add_view(self,request): 44 ModelFormDemo = self.get_modelform_class() 45 46 if request.method == 'POST': 47 form = ModelFormDemo(request.POST) 48 if form.is_valid(): 49 form.save() 50 51 return redirect(self.get_list_url()) 52 53 54 form = ModelFormDemo() 55 return render(request,'add.html',locals())
可以发现,这里比前面一章里多了几个方法,因为我们在后面的视图中可能会用到一些特定的url,如何获取到这些url就被封装成函数放在类里。
form组件的实现是从第30行开始的。首先我们声明类过程中先定义了一个变量modelform_class,值是空,是在没用指定要求的form效果时使用的(默认情况)。
通过第31行的if条件判断,如果单实例对象site里的键值对里的value,也就是配置类里没有自定义的form组件时就自己定义一个form组件类,然后把这个类返回给add视图里,经过实例化生成一个对象,ModelFormDemo,后面的过程就是正常的from组件的使用了。这里的数据校验没有什么特别要注意的敌方,所以没有加钩子什么的,直接用就行了。
对应的html代码
由于我们在视图返回的render里直接调用了locas()方法,会把函数内所有的变量传给模板,所以我们只需要关心的就是变量form。
1 <body> 2 <h3>添加页面</h3> 3 <div class="container"> 4 <div class="col-md-8 col-md-offset-4"> 5 <form action="" method="post"> 6 {%csrf_token%} 7 {%for field in form%} 8 <div> 9 <label for="">{{field.label}}</label> 10 </div> 11 {{field}} 12 {%endfor%} 13 <button class="btn btn-success pull-right">tijiao</button> 14 </form> 15 </div> 16 </div> 17 18 </body>
整个过程就是通过一个for循环吧form里的内容迭代出来,没什么要注意的,显示出来的效果很low
样式太难看,还是可以利用bootstrap的效果来美化一下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>添加数据</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> <script src="/static/jquery-3.2.1.min.js"></script> <link rel="stylesheet" href="/static/css/add.css"> <!-- <link rel="stylesheet" href="/static/css/add.css"> --> </head>
在head里导入bootstrap的css和jQuery的文件,然后需要自定义一下input标签,把css代码放进了add.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; }
出来的效果还稍微好一些,由于这里不让前端占太多篇幅,先不考虑太多,看看大致的效果
这样就完成了数据的添加视图的大致内容。
数据修改
数据的修改和添加时一样的,先看一下代码
1 def change_view(self,request,id): 2 ModelFormDemo = self.get_modelform_class() 3 edit_obj = self.model.objects.filter(pk = id).first() 4 if request.method == 'POST': 5 form = ModelFormDemo(request.POST) 6 if form.is_valid(): 7 form.save() 8 return redirect(self.get_list_url()) 9 10 form = ModelFormDemo(instance=edit_obj) 11 return render(request,'change.html',locals())
由于在RUL里包含了需要修改的数据的id,所以视图函数会多一个参数——id,id是通过URL里的正则获取到的。
整个代码的逻辑和添加的视图差不多,模板是一样的,通过locals方法传递的变量也是form,唯一一点不同的是在视图中通过id索引到需要修改的QuerySet,然后在实例化form对象的时候吧需要修改的对象赋值给form(通过参数instance,第10行里)
然后剩下的部分就和添加是一样的了
其实应该先做一个数据展示的视图,然后对每个book对象加上一个a标签,需要修改的时候点击这个标签直接跳转到这个页面。
上面的图就是直接访问url的效果
存在的BUG
整个修改的视图只是讲了一下逻辑过程,但是这里有一个BUG可以留着以后修改一下:
在实际生产环境,我们要修改对象的时候是通过点击相应的a标签进入修改的页面
注意上面动图里的URL,就是点击的change前面的4就是要修改Book对象的id。我们需要的是修改,但是上面的视图中是具备增加功能的。在地址栏中直接输入URL,id如果不存在的会直接弹出一个空白的form组件,和add视图一样。可以看一下代码,可以直接走到save()方法就在数据库里新增了一个book对象。这个明显是不利于权限管理的。所以要注意一下,怎么修改以后有机会再讲吧。