1. 程式人生 > >Django快速開發web前端

Django快速開發web前端

轉載自:http://www.furion.info/235.html

首先說下背景,日常工作中有很多時候都要求查詢一個域名是否在白名單中(業務相關的,實際就是一個檔案),所以很多的時候我們都不得不登上裝置,grep 下,不存在則新增進去。一次兩次還行,時間長了,也挺煩的,有時候就是簡單的查詢也需要登裝置,未免有點繁瑣了。so引入了本篇的主題,採用django 開發一個web前端去查詢、新增域名。

     先放下最終效果吧,首頁如下:

       

      採用了bootstrap的框架搭建的,實際可用的功能只能查詢、新增兩個。

      查詢頁面:

         

      新增頁面:

                                 

Contents [hide]

     1.分析需求:

          需求也挺簡單的,就是django搭一個web介面,由於域名 的名單是存在在一個檔案中的,所以所有的操作都是針對檔案的操作,而唯一需要互動的就是從客戶端獲取需要查詢、新增的域名即可,這部分通過POST實現。

        簡述如下:

        a)獲取客戶端資料(域名)

        b)開啟白名單檔案white.conf,搜尋是否匹配域名

        c)在白名單檔案尾部新增未匹配的域名

        大致是這麼一個很簡單的流程。

2.具體規劃:

        

        檔案樹如上,分為templates、white_list兩個資料夾,由於暫時沒有使用資料庫,就沒有建立app,因此沒有app的資料夾。 主要後端功能由views.py實現,相關的模板存在在templates資料夾中,urls.py負責檢視的展示。

        後端功能主要有views.py實現,具體劃分為三個檢視函式:

         index(request), search(request),add(request)。

         index主要負責首頁的展示,search負責域名的查詢功能,add則負責域名的新增功能。

3.index檢視函式的實現

         首先實現後端的功能吧,哎,前端是硬傷,看我的介面就知道了。前端傷不起啊,提一次傷一次。

        這裡首先首先後端的程式碼,程式碼如下:

def index(request):
    return render_to_response("index.html")return render_to_response("index.html")

         程式碼很簡單就是一個簡單的返回一個模板-index.html。

          index.html採用的是bootsharp實現的效果,相關的程式碼是我從django中文社群借鑑來的。後期不打算採用Bootsharp寫前端了,前端寫不好,這是命,得認。。

         程式碼如下:

<!DOCTYPE html>
  <head>
    <title>Twitter Bootstrap Tutorial - A responsive layout tutorial</title>
    <style type='text/css'>
      body {
        background-color: #CCC;
      }
    </style>
  </head>
  <body>
    <link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
<div class="container">
  <h1>TWITTER BOOTSTRAP TUTORIAL</h1>
  <div class='navbar navbar-inverse'>
    <div class='navbar-inner nav-collapse' style="height: auto;">
        <ul class="nav">
            <li class="active">
                <a href="#">Home</a>
            </li>
            <li>
                <a href="#">Page One</a>
            </li>
            <li>
                <a href="#">Page Two</a>
            </li>
        </ul>
    </div>
</div>
<div id='content' class='row-fluid'>
  <div class='span9 main'>
    <h2>Main Content Section</h2>
    <ul class="nav nav-tabs nav-stacked">
  <li><a href=''>Another Link 1</a></li>
  <li><a href='#'>Another Link 2</a></li>
  <li><a href='#'>Another Link 3</a></li>
</ul>
  </div>
  <div class='span3 sidebar'>
    <h2>Sidebar</h2>
  </div>
</div>

</div>
  </body>
</html>DOCTYPE html>
  <head>
    <title>Twitter Bootstrap Tutorial - A responsive layout tutorial</title>
    <style type='text/css'>
      body {
        background-color: #CCC;
      }
    </style>
  </head>
  <body>
    <link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
<div class="container">
  <h1>TWITTER BOOTSTRAP TUTORIAL</h1>
  <div class='navbar navbar-inverse'>
    <div class='navbar-inner nav-collapse' style="height: auto;">
        <ul class="nav">
            <li class="active">
                <a href="#">Home</a>
            </li>
            <li>
                <a href="#">Page One</a>
            </li>
            <li>
                <a href="#">Page Two</a>
            </li>
        </ul>
    </div>
</div>
<div id='content' class='row-fluid'>
  <div class='span9 main'>
    <h2>Main Content Section</h2>
    <ul class="nav nav-tabs nav-stacked">
  <li><a href=''>Another Link 1</a></li>
  <li><a href='#'>Another Link 2</a></li>
  <li><a href='#'>Another Link 3</a></li>
</ul>
  </div>
  <div class='span3 sidebar'>
    <h2>Sidebar</h2>
  </div>
</div>

</div>
  </body>
</html>

4.search檢視的實現:

       照例是後端程式碼,程式碼如下:

from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.core.context_processors import csrf
from django.template import RequestContext
import os

file = '/tmp/white.conf'
#to search the white list
def search_item(white_item):
    line_num = 0
    #find: 0 ,not find : 1
    find = 0
    message = 'not find %s ' % white_item
    white_file =  open(file)
    for line in white_file.readlines(): 
        line_num += 1
        if line.strip()  == white_item:
            message = 'find %s in %s line' %(white_item, line_num)
            #find :1
            find = 1
            break

    white_file.close()
    return (message,find)

def search(request):

    show_result = 0
    if request.method == 'POST':
            items =  request.POST.get('items', 'test'),
        white_items = items[0]
        white_items = white_items.split('rn')
        print items
        result = []
        show_result = 1
        for item in white_items:
        #get the search_item's message : 0 
        result.append(search_item(item)[0])    
        print result
            return render_to_response('search.html',{'result':result,'show_result':show_result})

    return render_to_response('search.html')'/tmp/white.conf'
#to search the white list
def search_item(white_item):
    line_num = 0
    #find: 0 ,not find : 1
    find = 0
    message = 'not find %s ' % white_item
    white_file =  open(file)
    for line in white_file.readlines(): 
        line_num += 1
        if line.strip()  == white_item:
            message = 'find %s in %s line' %(white_item, line_num)
            #find :1
            find = 1
            break

    white_file.close()
    return (message,find)

def search(request):

    show_result = 0
    if request.method == 'POST':
            items =  request.POST.get('items', 'test'),
        white_items = items[0]
        white_items = white_items.split('rn')
        print items
        result = []
        show_result = 1
        for item in white_items:
        #get the search_item's message : 0 
        result.append(search_item(item)[0])    
        print result
            return render_to_response('search.html',{'result':result,'show_result':show_result})

    return render_to_response('search.html')

     search_item函式是搜尋域名是否在白名單檔案中存在,因此add,search兩個檢視函式均會呼叫,所以寫成一個單獨的 search_item函式以便複用。message是搜尋域名時返回的一個字串,find是一個標準位,用以標準一個域名是否搜尋到,1表示搜尋 到,0表示未找到。search_item函式返回一個元組,其中包含message和find。

     這裡稍微解釋下為什麼返回一個元組:

     因為最開始實現 search_item函式的時候只實現了search檢視函式,而search檢視只需要無論查到與否都返回message給模板就可以了,所以是不需 要find標誌位的。但後來實現add檢視的時候,發現search_item函式只返回message的話無法直接的判定這個域名是否已經在白名單中存 在,所以後來額外返回了一個find標誌位供add檢視使用。

     對應的前端模板如下:

{% extends "base.html" %}

{% block title %}search the whilte list{% endblock %}

{% block content %}

<p>search the while list</p>
{% if show_result %}
    <ul>
        {% for res in result %}
        <li> {{ res }} </li>
        {% endfor %}
    </ul>

{% else %}
    <ul>
        <form action="/search/" method="post">
            <textarea name="items" cols="50" rows="10"></textarea>   
            <input type="submit" value="Add">
        </form>

    </ul>

{% endif %}

{% endblock %}<p>search the while list</p>
{% if show_result %}
    <ul>
        {% for res in result %}
        <li> {{ res }} </li>
        {% endfor %}
    </ul>

{% else %}
    <ul>
        <form action="/search/" method="post">
            <textarea name="items" cols="50" rows="10"></textarea>   
            <input type="submit" value="Add">
        </form>

    </ul>

{% endif %}

{% endblock %}

這個模板匯入了base.html模板,採用這種寫法主要是為了程式碼的複用,簡單點。其實你也可以直接寫死的,反正就一個表格的事兒。


base.html程式碼如下:

<!DOCTYPE HTML PUBLIC "//W3C//DTD HTML 4.01//EN"> 
<html lang="en"> 
<head> 
         <title>{% block title %}{% endblock %}</title> 
</head> 
<body> 
         <h1>CPIS white list manage</h1> 
         {% block content %}{% endblock %} 
         {% block footer %} 
     <hr> 
         <p>Any question please contact us,[email protected]</p> 
         {% endblock %} 
</body> 
</html> DOCTYPE HTML PUBLIC "//W3C//DTD HTML 4.01//EN"> 
<html lang="en"> 
<head> 
         <title>{% block title %}{% endblock %}</title> 
</head> 
<body> 
         <h1>CPIS white list manage</h1> 
         {% block content %}{% endblock %} 
         {% block footer %} 
     <hr> 
         <p>Any question please contact us,[email protected]</p> 
         {% endblock %} 
</body> 
</html> 

5. add檢視的實現

      後端程式碼如下:

def add(request):

    show_result = 0
    if request.method == 'POST':
            items =  request.POST.get('items', 'test'),
        white_items = items[0]
        white_items = white_items.split('rn')
        result = []
        show_result = 1
        #first find the all white_item
        for item in white_items:
        message  = search_item(item)
            find = message[1]    
        #if find the item ,then return the line  it matches
        if find :
            result.append(message[0])    
            
        #else  add item to the end
        else:
            white_file =  open(file,'a+')
            white_file.seek(0,2)
            white_file.write(item + os.linesep)
            white_file.close()
            message = 'add %s success ' % item
            result.append(message)

            return render_to_response('add.html',{'result':result,'show_result':show_result})

    return render_to_response('add.html')if request.method == 'POST':
            items =  request.POST.get('items', 'test'),
        white_items = items[0]
        white_items = white_items.split('rn')
        result = []
        show_result = 1
        #first find the all white_item
        for item in white_items:
        message  = search_item(item)
            find = message[1]    
        #if find the item ,then return the line  it matches
        if find :
            result.append(message[0])    
            
        #else  add item to the end
        else:
            white_file =  open(file,'a+')
            white_file.seek(0,2)
            white_file.write(item + os.linesep)
            white_file.close()
            message = 'add %s success ' % item
            result.append(message)

            return render_to_response('add.html',{'result':result,'show_result':show_result})

    return render_to_response('add.html')

      各個檢視中使用result儲存最終的返回值,用以渲染模板。show_result同樣也是一個標誌位,當然還是要從最初的設計說起:最初的設計是由四個檢視的,分別是search_form,search_item,add_form,add_item。

        其中search_form和add_form用以呈現搜尋、新增的表格,search_item和add_item用以實現真正的搜尋、新增操作,當然同樣需要有search_item.html,add_item.html等四個模板檔案。

        這樣功能上是實現了,但程式碼很亂、不能服用,而且導致urls.py中同樣很凌亂,參考了《django book 2.0》中的程式碼,將search_form,add_form檢視刪除,所有的表格顯示、結果顯示放到一個模板中實現了。因此就需要判定什麼時候顯示錶格,什麼時候顯示搜尋或者新增的結果,故引入了show_result標誌位,為1的時候表示顯示結果,0則顯示新增或者搜尋表格。

       對應的前端程式碼:

{% extends "base.html" %}

{% block title %}Add the item into whilte list{% endblock %}

{% block content %}

<p>Add the white item</p> 
{% if show_result %}
    <ul>
        {% for res in result %}
        <li> {{ res }} </li>
        {% endfor %}
    </ul>

{% else %}
    <ul>
        <form action="/add/" method="post">
            <textarea name="items" cols="50" rows="10"></textarea>
            <input type="submit" value="Add">

    </ul>
{% endif %}

{% endblock %}<p>Add the white item</p> 
{% if show_result %}
    <ul>
        {% for res in result %}
        <li> {{ res }} </li>
        {% endfor %}
    </ul>

{% else %}
    <ul>
        <form action="/add/" method="post">
            <textarea name="items" cols="50" rows="10"></textarea>
            <input type="submit" value="Add">

    </ul>
{% endif %}

{% endblock %}

       同樣匯入了base.html檔案。當然同樣的,你也可以寫死為個表格進去,無所謂的事情了。

6.urls.py檔案

          urls.py則負責檢視的顯示。程式碼如下:

from django.conf.urls import patterns, include, url
from django.conf import settings

# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

from white_list.views import index
from white_list.views import add
from white_list.views import search

urlpatterns = patterns('',
    # Examples:
    # url(r'^$', 'white_list.views.home', name='home'),
    # url(r'^white_list/', include('white_list.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),
    ('^$',index),
    ('^index/$',index),
    ('^add/$',add),
    ('^search/$',search),
)'',
    # Examples:
    # url(r'^$', 'white_list.views.home', name='home'),
    # url(r'^white_list/', include('white_list.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),
    ('^$',index),
    ('^index/$',index),
    ('^add/$',add),
    ('^search/$',search),
)

       (‘^$’,index),  和(‘^index/$’,index), 這兩個url均呼叫index()檢視函式。即開啟首頁可以採用http:ip/ 和http:ip/index這兩種方式。(‘^add/$’,add),(‘^search/$’,search),分別匹配add,search檢視函式。

7.除錯工具

             其實我覺得寫好後端的時候就可以開始除錯後端了,只是寫好後端的時候還沒有任何前端,除錯起來不方便。google半天,找個一個不錯的工具,httprequester。

          

         httprequester可以方便的對伺服器發起各種請求,GET、POST、PUT,傳送特定head頭,傳送需要POST的引數等,同時會記錄每個請求的返回碼以及歷史記錄,極為犀利,比同等次的Poster要好用。推薦在後端寫好的時候就採用httprequester測試下後端程式碼是否正常。


         這裡我是針對後端發起了一次POST請求,引數為item=’furion’,用以檢測後端能否正常接收POST上來的引數,可以看出後端響應200,同時返回了我搜索的域名。說明後端程式碼基本測試通過。


          如果訪問的時候出現"django, CSRF token missing or incorrect " ,則是因為預設django開啟了防跨站攻擊的安全策略,解決辦法由很多,我這裡禁用了csrf。自行百度吧。

           如果關閉debug模式出現500錯誤,則需要設定setting.py中的ALLOWED_HOSTS 列表,預設為空,即非debug模式不允許任何人訪問,需要手動修改。

8.總結

      其實搞個web介面是挺爽的一件事,但用著爽,寫起來就麻煩了,這個非常簡單的需求,我寫起來前前後後也倒騰了很久。有些事情說起來容易,看起來也容易,但做起來還是不容易的,始知萬事親歷才有資格說easy.

後續工作:

       a)使用者驗證:

              其實現在基本的功能已經實現了,但由於這個白名單的事情比較關鍵,所以必須有相應的使用者驗證,只需要登入使用者才可以新增名單,所以這方便還需要做一個使用者認證機制。

      b)日誌:

            後續可以實現一個日誌系統,查詢某個時間段、某個域名的操作記錄等,方便問題的追溯。