Django运维后台的搭建之三:用url去精细定制与反向解析

本文涉及的产品
云服务器 ECS,每月免费额度280元 3个月
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云服务器ECS,u1 2核4GB 1个月
简介:

上一篇文章里,我们做了一个alionlineecs(阿里云线上环境服务器)的添加界面,但是要知道我们的计划里是有六个分支的,而alionlineecs仅仅是其中之一,要是每一个都这么写的话,那么views.py肯定又臭又长,充满了大量的复制片段。


对于这样的情况,我们就用一种统一的方式,把这些alionlineecs\alifuncecs\slb\rds等等这些分支当成一个变量,再自定义两个url,比如lists这个url就是展示功能,当在浏览器里输入"外网地址:8000/lists/alionlinecs"的时候,就会出现阿里线上环境服务器的展示界面;当在浏览器里输入"外网地址:8000/lists/slb"的时候,就会出现阿里负载均衡的展示界面。同时也额外设定一个add的url,当在浏览器里输入"外网地址:8000/add/alionlinecs"的时候,就会出现阿里线上环境服务器的添加界面。这样就同意好管理多了。


于是我们先编辑vim forms.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
# -*- coding: UTF-8 -*-  
from  django.forms  import  ModelForm
from  .models  import  alionlineECS,alifuncECS,ksonlineECS,ksfuncECS,SLB,RDS
#定义ECS的Form,Form名字为 模式名+Form
class  alionlineForm(ModelForm):
     #自定义ModelForm的内容
     class  Meta:
         #该ModelForm参照Model: ECS
         model  =  alionlineECS
         #在Form中不显示node_signer这个字段  
         exclude  =  [ 'ecs_signer' ]
         
class  alifuncForm(ModelForm):
     class  Meta:
         model  =  alifuncECS
         exclude  =  [ 'ecs_signer' ]
         
class  ksonlineForm(ModelForm):
     class  Meta:
         model  =  ksonlineECS
         exclude  =  [ 'ecs_signer' ]
         
class  ksfuncForm(ModelForm):
     class  Meta:
         model  =  ksfuncECS
         exclude  =  [ 'ecs_signer' ]
         
class  SLBForm(ModelForm):
     class  Meta:
         model  =  SLB
         exclude  =  [ 'slb_signer' ]
         
class  RDSForm(ModelForm):
     class  Meta:
         model  =  RDS
         exclude  =  [ 'rds_signer' ]


然后把urls.py进行一下整顿:

1
2
3
4
5
6
7
8
from  django.conf.urls  import  url
from  django.contrib  import  admin
import  Online.views
urlpatterns  =  [
     url(r '^admin/' ,admin.site.urls),
     url(r '^lists/(?P<table>\w+)/$' ,Online.views.lists,name = 'lists' ),
     url(r '^add/(?P<table>\w+)/$' ,Online.views.add,name = 'add' ),
]


最麻烦的地方就是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
67
68
69
70
71
# -*- coding: UTF-8 -*-
from  django.shortcuts  import  render,redirect
from  .models  import  alionlineECS,alifuncECS,ksonlineECS,ksfuncECS,SLB,RDS
from  forms  import  alionlineForm,alifuncForm,ksonlineForm,ksfuncForm,SLBForm,RDSForm
def  lists(request,table):
         #不同的需求跳到不同的界面
         if  table  = =  'alionlineECS' :
         data  =  alionlineECS.objects. all ()
         list_template  =  'alionlineECS_list.html'
     if  table  = =  'alifuncECS' :
         data  =  alifuncECS.objects. all ()
         list_template  =  'alifuncECS_list.html'
     if  table  = =  'ksonlineECS' :
         data  =  ksonlineECS.objects. all ()
         list_template  =  'ksonlineECS_list.html'
     if  table  = =  'ksfuncECS' :
         data  =  ksfuncECS.objects. all ()
         list_template  =  'ksfuncECS_list.html'
     if  table  = =  'SLB' :
         data  =  SLB.objects. all ()
         list_template  =  'slb_list.html'
     if  table  = =  'RDS' :
         data  =  RDS.objects. all ()
         list_template  =  'rds_list.html'
         #建立一个context,将值传递到对应的页面
     context  =  {
         'data' :data,
     }
         #跳转到相应页面,并将具体的值传递过去
     return  render(request,list_template,context)
def  add(request,table):
     #根据提交的请求不同,获取来自不同Form的表单数据
     if  table  = =  'alionlineECS' :
         form  =   alionlineForm(request.POST  or  None )
     if  table  = =  'alifuncECS' :
         form  =   alifuncForm(request.POST  or  None )
     if  table  = =  'ksonlineECS' :
         form  =   ksonlineForm(request.POST  or  None )
     if  table  = =  'ksfuncECS' :
         form  =   ksfuncForm(request.POST  or  None )
     if  table  = =  'SLB' :
         form  =   SLBForm(request.POST  or  None )
     if  table  = =  'RDS' :
         form  =   RDSForm(request.POST  or  None )
     #判断form是否有效
     if  form.is_valid():
         #创建实例,需要做些数据处理,暂不做保存
         instance  =  form.save(commit = False )
         #将登录用户作为登记人
         if  table  = =  'alionlineECS' :
                 instance.ecs_signer  =  request.user
             if  table  = =  'alifuncECS' :
                 instance.ecs_signer  =  request.user
             if  table  = =  'ksonlineECS' :
                 instance.ecs_signer  =  request.user
             if  table  = =  'ksfuncECS' :
                 instance.ecs_signer  =  request.user
             if  table  = =  'SLB' :
                 instance.slb_signer  =  request.user
             if  table  = =  'RDS' :
                 instance.rds_signer  =  request.user
         #保存该实例
         instance.save()
         #跳转至列表页面  
         return  redirect( 'lists' ,table = table)
     #创建context来集中处理需要传递到页面的数据 
     context  =  {
         'form' : form,
     }
     #如果没有有效提交,则仍留在原来页面  
     return  render(request,  'add.html' ,context)


上面我们写了很多个html,那么现在就要一个一个的补全这些html,比如alionlineECS_list.html,这里放上我们需要对外展示的节点,注意要跟model.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
     < meta  charset = "UTF-8" >  
     < title ></ title >  
</ head >
< body >
     < table >
         < tr >
             < th >云服务器名称</ th >
             < th >云服务器类型</ th >
             < th >云服务器内网地址</ th >
             < th >云服务器外网地址</ th >
             < th >云服务器外网带宽</ th >
             < th >云服务器配置</ th >
             < th >备注</ th >
             < th >登记人</ th >
         </ tr >
         {% for item in data %}
             < tr >
                 < td >{{ item.ecs_name }}</ td >
                 < td >{{ item.ecs_type }}</ td >
                 < td >{{ item.ecs_inip }}</ td >
                 < td >{{ item.ecs_outip }}</ td >
                 < td >{{ item.ecs_ipwidth }}</ td >
                 < td >{{ item.ecs_spec }}</ td >
                 < td >{{ item.ecs_remarks }}</ td >
                 < td >{{ item.ecs_signer }}</ td >
             </ tr >
         {% endfor %}
     </ table >
</ body >
</ html >


而SLB.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
<!DOCTYPE html>
< html >
< head  lang = "en" >  
     < meta  charset = "UTF-8" >  
     < title ></ title >  
</ head >
< body >
     < table >
         < tr >
             < th >负载均衡名称</ th >
             < th >网络类型</ th >
             < th >转发规则</ th >
             < th >ip地址</ th >
             < th >负载均衡协议</ th >
             < th >前端端口</ th >
             < th >后端端口</ th >
             < th >负载均衡协议</ th >
             < th >前端端口</ th >
             < th >后端端口</ th >
             < th >登记人</ th >
             < th >备注</ th >
         </ tr >
         {% for item in data %}
             < tr >
                 < td >{{ item.slb_name }}</ td >
                 < td >{{ item.slb_type }}</ td >
                 < td >{{ item.slb_algorithm }}</ td >
                 < td >{{ item.slb_ip }}</ td >
                 < td >{{ item.slb_protocol }}</ td >
                 < td >{{ item.slb_fport }}</ td >
                 < td >{{ item.slb_bport }}</ td >
                 < td >{{ item.slb_protocol2 }}</ td >
                 < td >{{ item.slb_fport2 }}</ td >
                 < td >{{ item.slb_bport2 }}</ td >
                 < td >{{ item.slb_signer }}</ td >
                 < td >{{ item.slb_remarks }}</ td >
             </ tr >
         {% endfor %}
     </ table >
</ body >
</ html >


RDS.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
<!DOCTYPE html>
< html >
< head  lang = "en" >  
     < meta  charset = "UTF-8" >  
     < title ></ title >  
</ head >
< body >
     < table >
         < tr >
             < th >数据库名称</ th >
             < th >数据库类型</ th >
             < th >mysql版本</ th >
             < th >数据库规格</ th >
             < th >备注</ th >
             < th >数据库地址</ th >
             < th >存储空间</ th >
             < th >登记人</ th >
         </ tr >
         {% for item in data %}
             < tr >
                 < td >{{ item.rds_name }}</ td >
                 < td >{{ item.rds_type }}</ td >
                 < td >{{ item.rds_mysql }}</ td >
                 < td >{{ item.rds_spec }}</ td >
                 < td >{{ item.rds_remark }}</ td >
                 < td >{{ item.rds_ip }}</ td >
                 < td >{{ item.rds_status }}</ td >
                 < td >{{ item.rds_signer }}</ td >
             </ tr >
         {% endfor %}
     </ table >
</ body >
</ html >


这个时候我们启动django来到浏览器里,在地址栏输入:外网地址:8000/lists/alionlinecs,就会看到之前的那个添加“阿里云线上服务器”的界面,如图:

wKiom1lvEyzQlngVAAC0aSkWyiY066.png


在点击了提交之后,就会看到地址栏里的add变成了lists,达到了我们的预期目标:

wKiom1lvE6WT5s87AADMT6LNsoA671.png



在这篇文章的最后,我直接复制了http://blog.csdn.net/alex_chen_16/article/details/50850435 里对url处理请求的原理简述,留作备份和日后改进的参考。


1.      Django处理请求的方式

1) Django通过URLconf模块来进行判断。通常情况下,这就是ROOT_URLCONF配置的价值,但是如果请求携带了一个urlconf的属性(通常被中间件设置),那么这个被携带的urlconf将会替代ROOT_URLCONF的配置。

2) Django会调用Python模块并寻找各种urlpatterns。这是一个属于django.conf.urls.url()实例的python列表。

3) Django会遍历每个URL pattern,自上而下,并且选取收割匹配请求URL的pattern。

4) 一旦匹配某个url pattern的正则表达式,Django将导入并调用相关的view(这是一个简单的python函数,或者是一个class-based view)

这个view将会传递下列参数:

l  一个HttpRequest的实例

l  如果匹配了URL中一个no named group,那么参数将会按根据URL中的位置一一对应

l  如果匹配了URL中一个named group,且参数传递是通过named group来匹配的,那么参数将会被指定的kwargs代替。

5)  如果没有任何一个正则表达式被匹配,那么Django会抛出异常,并报错。


2. URL中的named  group

URL可以通过named group方式传递指定参数,语法为: (?P<name>pattern), name 可以理解为所要传递的参数的名称,pattern代表所要匹配的模式。例如,

  1. url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),  

那么year,month将会对应views传递过来的year,month的值,而后面紧跟的则代表正则表达匹配的模式。


3. URL的反向解析
通常来说在处理完一个表单之后,网页会发生跳转。通常写URL我们都避免硬编码,这样不方便后期的调整。通常我们需要从URL获取两种内容,最主要是view能够通过URL获取一些标识并处理,另一些信息则是传递过来的参数。
Django提供了一种解决方案,URL mapper是与URL设计一一对应。你可以通过URLconf来实现,并反向使用它。例如:

  • 由用户通过浏览器发起URL请求,调用view,并将URL中的参数传递给view

  • 通过view并附上相应参数,找到相应匹配的URL。

后者我们称之为对URLs的反向解析。反向解析的例子,

  1. url(r'^articles/([0-9]{4})/$', views.year_archive, name='news-year-archive'),  


Django在不同的层次也提供了一些工具来实现URL的反向解析。

  • 在template中:使用url标签

  • 在python中:使用django.core.urlresolvers.reverse()函数

  • 在更高层次处理model实例时,可以使用get_absolute_url()方法




 本文转自 苏幕遮618 51CTO博客,原文链接:http://blog.51cto.com/chenx1242/1948971
相关文章
|
15天前
|
网络协议 Linux 网络安全
Linux服务器DNS服务器配置实现bind的正向解释和反向解释
Linux服务器DNS服务器配置实现bind的正向解释和反向解释
17 0
|
8月前
|
弹性计算 缓存 运维
【运维知识进阶篇】用阿里云部署kod可道云网盘(DNS解析+CDN缓存+Web应用防火墙+弹性伸缩)(三)
【运维知识进阶篇】用阿里云部署kod可道云网盘(DNS解析+CDN缓存+Web应用防火墙+弹性伸缩)(三)
127 0
|
1月前
|
运维 监控 安全
运维工程师的转型与升级:解析35岁半衰期现象及其应对策略
运维工程师的转型与升级:解析35岁半衰期现象及其应对策略
79 1
|
6月前
|
应用服务中间件 Apache nginx
关于 SAP Spartacus 重定向部分外部 url 到后台系统的问题
关于 SAP Spartacus 重定向部分外部 url 到后台系统的问题
49 0
|
7月前
|
前端开发 JavaScript 数据库
Django系列:Django的项目结构与配置解析
本文讲解Django的项目结构与配置
160 0
|
8月前
|
弹性计算 缓存 运维
【运维知识进阶篇】用阿里云部署kod可道云网盘(DNS解析+CDN缓存+Web应用防火墙+弹性伸缩)(二)
【运维知识进阶篇】用阿里云部署kod可道云网盘(DNS解析+CDN缓存+Web应用防火墙+弹性伸缩)(二)
122 0
|
8月前
|
缓存 弹性计算 运维
【运维知识进阶篇】用阿里云部署kod可道云网盘(DNS解析+CDN缓存+Web应用防火墙+弹性伸缩)(一)
【运维知识进阶篇】用阿里云部署kod可道云网盘(DNS解析+CDN缓存+Web应用防火墙+弹性伸缩)
154 0
|
9月前
|
API
解决微信后台禁用url问题
由于目前用的平台,域名都没有在微信授权,所以被微信给禁用了,我们现在用一个接口可以绑定域名的平台转发一下,演示选择使用vscode工具,其它有终端的工具亦可。
解决微信后台禁用url问题
|
9月前
|
运维 网络协议 大数据
一站式运维管家 ChengYing 主机接入原理解析
之前的文章中,我们已经为大家介绍了 ChengYing 的安装原理、产品包制作、产品线部署等内容,本篇将和大家介绍一个困扰许多开发者的内容——ChengYing 主机接入。帮助所有对 ChengYing 感兴趣的开发者更好地了解和使用一站式全自动化运维管家 ChengYing。
66 0
|
11月前
|
数据库 Python
django drf 实现只有超级用户才能注册账号(涉及自定义权限permissions,获取token信息解析token信息)
django drf 实现只有超级用户才能注册账号(涉及自定义权限permissions,获取token信息解析token信息)

推荐镜像

更多