1. 程式人生 > >Django運維後臺的搭建之三:用url去精細定制與反向解析

Django運維後臺的搭建之三:用url去精細定制與反向解析

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代表所要匹配的模式。例如,

  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()方法

本文出自 “生活就是等待戈多” 博客,請務必保留此出處http://chenx1242.blog.51cto.com/10430133/1948971

Django運維後臺的搭建之三:用url去精細定制與反向解析