Django運維後臺的搭建之三:用url去精細定制與反向解析
上一篇文章裏,我們做了一個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:
# -*- 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進行一下整頓:
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,這個變動比較大了:
# -*- 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的各項一一對應:
<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就長這個樣子:
<!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寫成這個樣子:
<!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,就會看到之前的那個添加“阿裏雲線上服務器”的界面,如圖:
在點擊了提交之後,就會看到地址欄裏的add變成了lists,達到了我們的預期目標:
在這篇文章的最後,我直接復制了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代表所要匹配的模式。例如,
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的反向解析。反向解析的例子,
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()方法
本文出自 “生活就是等待戈多” 博客,請務必保留此出處http://chenx1242.blog.51cto.com/10430133/1948971
Django運維後臺的搭建之三:用url去精細定制與反向解析