背景说明
python:3.6.5
Django:2.1.1
Project:Kubernetes
,文件夹路径就是/django/Kubernetes/
App:createyaml
,文件夹路径就是/django/Kubernetes/createyaml
前文地址:https://rorschachchan.github.io/2018/09/18/Django%E9%80%9A%E8%BF%87%E5%94%AF%E4%B8%80%E6%A0%87%E8%AF%86%E7%AC%A6%E5%B0%86%E5%90%8E%E5%8F%B0%E6%95%B0%E6%8D%AE%E5%BA%93%E5%AF%B9%E5%BA%94%E8%BE%93%E5%87%BA/
需求与解决思路
对于表单而言,检查用户输入的信息是否合法是必然项。检查合法一般来说都是用JavaScript
或JQuery
。不过我是一个前端白痴,JavaScript
对我来说就是天书。但是Django非常的贴心,在form表单里就准备了“验证输入内容”这个功能。
如果使用这个功能,首先先在app的views.py
里导入form模块:from django import forms
。
导入模块之后,设定一个类,这个类就是要在前端html页面中生成form表单中的input
标签的,比如:
1
2
3
4
5
6class YamlInfo(forms.Form): #定义的django表单
name = forms.CharField(error_messages={'required': u'此节点不能为空'},) #自定义错误信息
replicas = forms.DecimalField(max_digits=2,error_messages={'required': u'副本个数不能大于100'}) #最大只有2位数
labels_app = forms.CharField(error_messages={'required': u'此节点不能为空'})
containers_name = forms.CharField(error_messages={'required': u'此节点不能为空'})
containers_image = forms.CharField(error_messages={'required': u'此节点不能为空'})
表单上输入的东西可能会有很多,根据实际情况哪些字段不能为空就把那些字段写到这个class里,在上面那个YamlInfo
里把这五项配置对应的Django表单字段,比如replicas
,这个字节代表的是容器副本个数
,所以它只能是数字,而且我们不要求它大于100,就设定max为2。
创建完类之后,需要在html页面里根据类的对象创建html标签,然后再提交的时候,需要后台views.py
把前端页面提交的数据封装到一个对象里:obj = YamlInfo(request.POST)
。由于每个Django表单的实例都有一个内置的is_valid()
方法,用来验证接收的数据是否合法。如果所有数据都合法,那么该方法将返回True
,并将所有的表单数据转存到它的一个叫做cleaned_data
的属性中,该属性是以个字典类型数据,然后对这组数据进行展示或者保存到数据库就随你便了;如果有一个数据是非法的,就可以return一个别的结果。
实际代码
理论到此结束,先看views.py
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67from django.shortcuts import render,render_to_response
from django.http import HttpResponse
from .models import parameter #引入数据库里的类
from django import forms #引入模块
class YamlInfo(forms.Form): #定义的django表单
name = forms.CharField(error_messages={'required': u'此节点不能为空'},)
replicas = forms.DecimalField(max_digits=2,error_messages={'required': u'副本个数不能大于100'}) #最大只有2位数
labels_app = forms.CharField(error_messages={'required': u'此节点不能为空'})
containers_name = forms.CharField(error_messages={'required': u'此节点不能为空'})
containers_image = forms.CharField(error_messages={'required': u'此节点不能为空'})
#create_yaml就是用来展示输入的页面而已
def create_yaml(request):
obj = YamlInfo() #创建form的对象
return render(request,'create_yaml.html',{'obj':obj}) #返回create_yaml这个模板,模板里的内容其实都是空的
#yaml_list就是展示所有的输入情况
def yaml_list(request):
obj = YamlInfo() #创建form的对象
if request.method == 'POST':
input_obj = YamlInfo(request.POST) #request.POST为提交过来的所有数据
if input_obj.is_valid():
data = input_obj.clean() #用clean()函数获取提交的数据
apiVersion = request.POST.get('apiVersion','v1') #POST.get方法获取到非form的对象
kind = request.POST.get('kind','RC')
name = data['name'] #用data字典来获取form的对象
replicas = data['replicas']
labels_app = data['labels_app']
containers_name = data['containers_name']
containers_image = data['containers_image']
containerPort1 = request.POST.get('containerPort1',None)
containerPort2 = request.POST.get('containerPort2',None)
containers_name2 = request.POST.get('containers_name2',None)
containers_image2 = request.POST.get('containers_image2',None)
containerPort2_1 = request.POST.get('containerPort2_1',None)
containerPort2_2 = request.POST.get('containerPort2_2',None)
print (data) #可以在后台看到整个data的内容
else: #如果输入不合法,返回错误信息
error_msg = input_obj.errors #errors为错误信息
return render(request,'create_yaml.html',{'obj':input_obj,'errors':error_msg}) #将错误信息直接返回到前端页面去展示,刚刚输入的非法字段也保留
else: #如果不是post提交,那么就是展示数据里的情况
yamls = parameter.objects.all().order_by('-id') #以倒数展示,即新加的在上面
context = {}
context['yamls'] = yamls
return render_to_response('yaml_list.html',context) #返回yaml_list.html,里面有数据库的所有数据
Parameter = parameter() #将数据库的类实例化
Parameter.apiVersion = apiVersion
Parameter.kind = kind
Parameter.name = name
Parameter.replicas = replicas
Parameter.labels_app = labels_app
Parameter.containers_name = containers_name
Parameter.containers_image = containers_image
Parameter.containerPort1 = containerPort1
Parameter.containerPort2 = containerPort2
Parameter.containers_name2 = containers_name2
Parameter.containers_image2 = containers_image2
Parameter.containerPort2_1 = containerPort2_1
Parameter.containerPort2_2 = containerPort2_2
Parameter.save() #保存这些到数据库里
yamls = parameter.objects.all().order_by('-id')
context = {}
context['yamls'] = yamls
return render_to_response('yaml_list.html',context)
配置一下urls.py
:
1
2
3
4
5
6
7
8
9from django.contrib import admin
from django.urls import path
from createyaml import views #将app的views.py文件引入
urlpatterns = [
path('admin/', admin.site.urls), #每个页面对应各自在views.py里的函数
path(r'create_yaml/', views.create_yaml),
path(r'yaml_list/', views.yaml_list),
]
配置一下用户输入的界面—create_yaml.html
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>生成K8S所用的YAML文件</title>
</head>
<body>
<h1>用户输入</h1>
<h2>请注意!大小写敏感!!!</h2>
<form action="/yaml_list/" method="post" name='yamllist'>
{% csrf_token %}
API版本:
<select name='apiVersion'>
<option value="v1" selected>v1</option>
<option value="extensions/v1beta1">beta1</option>
</select><br />
任务类型:
<select name='kind'>
<option value="Pod" selected>Pod</option>
<option value="Service">Service</option>
<option value="Deployment">Deployment</option>
<option value="ReplicationController">ReplicationController</option>
</select><br />
<p>任务名称:{{ obj.name }} <span>{{ errors.name }}</span></p>
<p>任务数量:{{ obj.replicas }} <span>{{ errors.replicas }}</span></p>
<p>APP名称:{{ obj.labels_app }} <span>{{ errors.labels_app }}</span></p>
<p>容器1名称:{{ obj.containers_name }} <span>{{ errors.containers_name }}</span></p>
<p>容器1镜像:{{ obj.containers_image }} <span>{{ errors.containers_image }}</span></p>
容器1开放端口1:<input type="text" placeholder="没有可以不填" name="containerPort1" /><br />
容器1开放端口2:<input type="text" placeholder="没有可以不填" name="containerPort2" /><br />
容器2名称:<input type="text" placeholder="没有可以不填" name="containers_name2" /><br />
容器2镜像:<input type="text" placeholder="没有可以不填" name="containers_image2" /><br />
容器2开放端口1:<input type="text" placeholder="没有可以不填" name="containerPort2_1" /><br />
容器2开放端口2:<input type="text" placeholder="没有可以不填" name="containerPort2_2" /><br />
<input type="reset" value="清除所有" />
<input type="submit" value="生成yaml文件" />
</form>
</body>
</html>
而跳转后的yaml_list.html
就是这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>yaml文件展示</title>
</head>
<body>
<h1>数据库里的yaml数据展示</h1>
<table width="100%" border="1">
<thead>
<a href="http://121.41.37.251:33664/create_yaml/"><button>返回</button></a>
<!--插入按钮 开始-->
<input type="button" value="执行" onclick="MsgBox()" />
<!--插入按钮 结束-->
<!--引用JS代码以达到弹出对话框目的 开始-->
<script language="javascript">
function MsgBox() //声明标识符
{
confirm("确定要执行后台脚本么?"); //弹出对话框
}
</script>
<!--引用JS代码以达到弹出对话框目的 结束-->
<br>
<form>
<tr>
<td align="center">任务序号</td>
<td align="center">yaml名称</td>
<td align="center">api版本</td>
<td align="center">任务类型</td>
<td align="center">任务数量</td>
<td align="center">对应应用</td>
<td align="center">使用的第一个镜像名称</td>
<td align="center">镜像1的第一个端口</td>
<td align="center">镜像1的第二个端口</td>
<td align="center">使用的第二个镜像名称</td>
<td align="center">镜像2的第一个端口</td>
<td align="center">镜像2的第二个端口</td>
</tr>
</thead>
<tbody>
{% for yaml in yamls %}
<tr>
<td><input type="radio" name="id" checked="checked"/>{{ yaml.id }} </td>
<td align="center">{{ yaml.name }} </td>
<td align="center">{{ yaml.apiVersion }}</td>
<td align="center">{{ yaml.kind }}</td>
<td align="center">{{ yaml.replicas }}</td>
<td align="center">{{ yaml.labels_app }}</td>
<td align="center">{{ yaml.containers_image }}</td>
<td align="center">{{ yaml.containerPort1 }}</td>
<td align="center">{{ yaml.containerPort2 }}</td>
<td align="center">{{ yaml.containers_image2 }}</td>
<td align="center">{{ yaml.containerPort2_1 }}</td>
<td align="center">{{ yaml.containerPort2_2 }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
启动django,我们来看一下效果!
不过说实话,对于用户来说,肯定选择题的感觉要比填空题好。所以到时候我们可以把阿里云容器仓库里的所有的镜像做成一个数据库,到时候映射到这个页面,让用户去在里面做选择而不是填空。而且django的form检查相比较JavaScript而言还是很粗糙的,如果是处女座的话,还是要搞JavaScript,而且两者也并不冲突,一个是对前端用户而言,一个是后台检查录入数据库的。
参考资料
https://docs.djangoproject.com/en/2.1/topics/forms/ (官方文档)
http://www.liujiangblog.com/course/django/152
https://www.cnblogs.com/chenchao1990/p/5284237.html
http://dokelung-blog.logdown.com/posts/221431-django-notes-8-form-validation-and-modeling
https://www.jb51.net/article/103135.htm