Django快速开发web前端

转载自:http://www.furion.info/235.html

 

 

首先说下背景,日常工作中有很多时候都要求查询一个域名是否在白名单中(业务相关的,实际就是一个文件),所以很多的时候我们都不得不登上设备,grep 下,不存在则添加进去。一次两次还行,时间长了,也挺烦的,有时候就是简单的查询也需要登设备,未免有点繁琐了。so引入了本篇的主题,采用django 开发一个web前端去查询、添加域名。

 

     先放下最终效果吧,首页如下:

       

 

      采用了bootstrap的框架搭建的,实际可用的功能只能查询、添加两个。

      查询页面:

         

 

      添加页面:

                                 

Contents [hide]

  • 1      1.分析需求:
  • 2 2.具体规划:
  • 3 3.index视图函数的实现
  • 4 4.search视图的实现:
  • 5 5. add视图的实现
  • 6 6.urls.py文件
  • 7  
  • 8 7.调试工具
  • 9              其实我觉得写好后端的时候就可以开始调试后端了,只是写好后端的时候还没有任何前端,调试起来不方便。google半天,找个一个不错的工具,httprequester。
  • 10 8.总结

     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 tutorialtitle>
    <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 TUTORIALh1>
  <div class='navbar navbar-inverse'>
    <div class='navbar-inner nav-collapse' style="height: auto;">
        <ul class="nav">
            <li class="active">
                <a href="#">Homea>
            li>
            <li>
                <a href="#">Page Onea>
            li>
            <li>
                <a href="#">Page Twoa>
            li>
        ul>
    div>
div>
<div id='content' class='row-fluid'>
  <div class='span9 main'>
    <h2>Main Content Sectionh2>
    <ul class="nav nav-tabs nav-stacked">
  <li><a href=''>Another Link 1a>li>
  <li><a href='#'>Another Link 2a>li>
  <li><a href='#'>Another Link 3a>li>
ul>
  div>
  <div class='span3 sidebar'>
    <h2>Sidebarh2>
  div>
div>

div>
  body>
html>DOCTYPE html>
  <head>
    <title>Twitter Bootstrap Tutorial - A responsive layout tutorialtitle>
    <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 TUTORIALh1>
  <div class='navbar navbar-inverse'>
    <div class='navbar-inner nav-collapse' style="height: auto;">
        <ul class="nav">
            <li class="active">
                <a href="#">Homea>
            li>
            <li>
                <a href="#">Page Onea>
            li>
            <li>
                <a href="#">Page Twoa>
            li>
        ul>
    div>
div>
<div id='content' class='row-fluid'>
  <div class='span9 main'>
    <h2>Main Content Sectionh2>
    <ul class="nav nav-tabs nav-stacked">
  <li><a href=''>Another Link 1a>li>
  <li><a href='#'>Another Link 2a>li>
  <li><a href='#'>Another Link 3a>li>
ul>
  div>
  <div class='span3 sidebar'>
    <h2>Sidebarh2>
  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 listp>
{% 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 listp>
{% 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 manageh1> 
         {% 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 manageh1> 
         {% 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 itemp> 
{% 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 itemp> 
{% 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)日志:

            后续可以实现一个日志系统,查询某个时间段、某个域名的操作记录等,方便问题的追溯。

 

你可能感兴趣的:(django)