Xadmin控件的实现:〇二增、改视图

我们在前一章里列出了整个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;
}
add.css

出来的效果还稍微好一些,由于这里不让前端占太多篇幅,先不考虑太多,看看大致的效果

 这样就完成了数据的添加视图的大致内容。

数据修改

数据的修改和添加时一样的,先看一下代码

 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对象。这个明显是不利于权限管理的。所以要注意一下,怎么修改以后有机会再讲吧。

原文地址:https://www.cnblogs.com/yinsedeyinse/p/13475072.html