1. 程式人生 > >【詳解】Python專題開發

【詳解】Python專題開發

使用Python從指令碼到專題開發,才知道為什麼會有人說Python大法好,別的都去死!

因為相較於JAVA,開發起來要爽太多,方方面面……

【需求】

1. 本例,因為著急上線一個新的活動版塊,所以使用Python來開發管理後臺。

2. 功能很簡單,增刪改查都實現即可。

3. 顯示部分要有分頁。

【Python專題分析】

Python專題(內部這麼叫),就是使用Python來開發一個網站。也就是Python Web應用開發。

專案結構如圖所示:


目錄結構從最大的資料夾開始,從上往下走------

moyoyo_zt資料夾和manage.py檔案,前者是工程程式碼所在,後者是執行工程關鍵檔案。

moyoyo_zt資料夾又分三個部分,硬程式碼所在資料夾jisumai,前臺頁面程式碼templates,其他四個檔案__init__.py、settings.py、urls.py、wsgi.py。

也就是說,除了我們比較熟悉的硬程式碼和前臺頁面程式碼,就剩下5個檔案需要格外注意:manage.py、__init__.py、settings.py、urls.py、wsgi.py。

我們一個個闡述。

【manage.py】

我們執行工程的時候執行的就是這個Python檔案。

#!/usr/bin/env python
import os
import sys

if __name__ == "__main__"
: os.environ.setdefault("DJANGO_SETTINGS_MODULE", "moyoyo_zt.settings") from django.core.management import execute_from_command_line execute_from_command_line(sys.argv)
 

使用 Django 時, 你必須告訴它你使用的是哪個 settings . 要做到這一點,使用環境變數DJANGO_SETTINGS_MODULE.

【__init__.py】

空檔案。

存在該檔案是因為:一個包是一個帶有特殊檔案 __init__.py

的目錄。

__init__.py 檔案定義了包的屬性和方法。其實它可以什麼也不定義;可以只是一個空檔案,但是必須存在。

如果 __init__.py 不存在,這個目錄就僅僅是一個目錄,而不是一個包,它就不能被匯入或者包含其它的模組和巢狀包。

也就是說,目錄下的.py檔案需要import引入包的時候,就需要在目錄中有這樣一個__init__.py

所以我們可以看到,在jisumai 的目錄下也有這樣一個__init__檔案

【settings.py】

這個檔案包含了所有有關這個Django專案的配置資訊

均大寫:   TEMPLATE_DIRS , DATABASE_NAME , 等.

最重要的設定是 ROOT_URLCONF,它將作為 URLconf 告訴 Django 在這個站點中那些 Python的模組將被用到。

不過這裡我們的這一項放到了urls.py檔案中

ROOT_URLCONF = 'moyoyo_zt.urls'   

使用 Django 時, 你必須告訴它你使用的是哪個 settings .

【urls.py】

定義了連結相關

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

from django.contrib import admin
admin.autodiscover()

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

【wsgi.py】

wsgi(Python Web Server Gateway Interface)伺服器閘道器介面,

是Python語言定義的web伺服器和web服務程式或者框架之間的一種簡單而通用的介面。

import os
import sys
sys.path.append("/usr/local/django_apps/moyoyo_zt/")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "moyoyo_zt.settings")

from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

大致瞭解了Python專題的工程結構,其實可以看出,Python專題依然是典型的MVC模式,前臺頁面,後臺程式碼,資料庫,配置檔案。。。

其實和springmvc挺像的,但是簡單了許多!

接下來正式開始開發,以實際開發的時間順序來進行闡述----------

【新建資料庫】

因為是新的模組,什麼都沒有。

最核心的資料需要有一個存放的地方,所以先要建立資料庫!~

建立資料庫的語句需要學會手寫,因為Navicat這樣的軟體只能在windows環境下使用,遠端的Linux伺服器根本沒有新建資料庫的軟體和介面。

這種情況下,就需要手寫SQL語句來對資料庫進行操作與更改。

新建資料庫並新增索引的語句:

CREATE TABLE QUICK_SELLING_GOODS(
    ID  int(11) NOT NULL AUTO_INCREMENT,
    SELLING_GOODS_ID  int(11) NOT NULL ,
    NAME  varchar(100) NOT NULL ,
    GAME_NAME  varchar(100) NOT NULL ,
    ORI_PRICE  int(11) NOT NULL ,
    COMMENTS  varchar(500) NOT NULL ,
    DETAILS  varchar(100) NOT NULL ,
    STATUS  smallint(6) NULL ,
    PRIMARY KEY (ID)
)ENGINE=INNODB DEFAULT CHARSET=utf8;
CREATE INDEX IX_QUICK_SELLING_GOODS_SELLING_GOODS_ID on QUICK_SELLING_GOODS (SELLING_GOODS_ID) 

【說明】
1. 儘量手寫
2. 建表語句後加一條
ENGINE=INNODB DEFAULT CHARSET=utf8;
指定編碼格式
3. SELLING_GOODS_ID需要加索引。
語句的寫法是:
CREATE INDEX IX_QUICK_SELLING_GOODS_SELLING_GOODS_ID on QUICK_SELLING_GOODS (SELLING_GOODS_ID) 
其中
IX_QUICK_SELLING_GOODS_SELLING_GOODS_ID
是索引名,命名規則是IX_資料庫名_欄位名。(IX是INDEX的縮寫)
這樣命名使索引名唯一。

執行.sql為副檔名的SQL檔案來建立資料表。

【修改資料庫】

遇到需要修改資料庫的情況。(欄位DETAILS長度不夠,需要從100擴充套件到500)

SQL修改語句如下:

ALTER TABLE QUICK_SELLING_GOODS MODIFY COLUMN DETAILS  varchar(500) not null;

原先是這樣寫的:
ALTER TABLE QUICK_SELLING_GOODS MODIFY COLUMN DETAILS  varchar(500);
發現這樣寫會把DETAILS的非空屬性改了。
所以要補上not null。



【django工程增刪改查 之 查】
也就是把資料庫的中資料顯示在頁面上。

前端頁面:backend.html
顯示部分程式碼如下:
<table width=1000 height=500 border="1">
  <tr bgcolor="lightgrey" height=10>
        <th width=150>商品ID</th>
        <th width=500>商品名稱</th>
        <th width=100>遊戲名稱</th>
        <th width=100>原價</th>
        <th width=150>操作</th>
        </tr>
{% for sellinggoods in goodslist %}
        <tr>
            <td>{{sellinggoods.SELLING_GOODS_ID}}</td>
            <td>{{sellinggoods.NAME}}</td>
            <td>{{sellinggoods.GAME_NAME}}</td>
            <td>{{sellinggoods.ORI_PRICE}}</td>
            <td>&nbsp;
<a href="javascript:void(0)" onclick="javascript:gotochange({{sellinggoods.SELLING_GOODS_ID}})">修改</a>&nbsp;&nbsp;
<a href="javascript:void(0)" onclick="javascript:confirm_del({{sellinggoods.SELLING_GOODS_ID}})">刪除</a></td>
        </tr>
{% endfor %}

</table></br>
用一個table來顯示所有內容。
關鍵部分的迴圈遍歷顯示,與java的原理其實是一樣的。只不過語法不同而已!
{% for sellinggoods in goodslist %}
<td>{{sellinggoods.SELLING_GOODS_ID}}</td>
{% endfor %}

回顧一下Java中的這部分程式碼

<c:forEach var="message" items="${model.message}">			
    <tr>   
        <td> <fmt:formatDate pattern="yyyy-MM-dd HH:mm" value="${message.createdDate}" type="date"/></td>
        <td> ${message.username}</td>
        <td> ${message.content}</td>
        <td> ${message.reply}</td>
    </tr>
</c:forEach>
使用的是forEach標籤。


後端程式碼:
使用Java實現顯示資料時,後端程式碼是這樣的結構。


即,典型的MVC架構模式。
而Python中這部分程式碼的架構是這樣的:

紅框是顯示功能需要的部分。

我們一一說明:
__init__.py 依然是空檔案,作用不再贅述。
models.py 中定義了資料類,即,把要顯示的資料封裝成類,方便在程式碼中傳遞。
from django.db import models

class SellingGoods(models.Model):
    ID = models.AutoField(primary_key=True)
    SELLING_GOODS_ID = models.IntegerField()
    NAME = models.CharField(max_length=100)
    GAME_NAME = models.CharField(max_length=100)
    ORI_PRICE = models.IntegerField()
    COMMENTS = models.CharField(max_length=500)
    DETAILS = models.CharField(max_length=100)
    STATUS = models.IntegerField()

    class Meta: 
        db_table = "QUICK_SELLING_GOODS"

urls.py 相當於java中的controller-action-config.xml


from django.conf.urls import patterns, include, url
from moyoyo_zt.jisumai.views import *

from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
# Examples:
    # url(r'^blog/', include('blog.urls')),
url(r'^$',index),
url(r'^index',index),
url(r'^details',details),
url(r'^backend',backend),
url(r'^delete',delete),
url(r'^gotoadd',gotoadd),
url(r'^add',add),
url(r'^gotochange',gotochange),
url(r'^change',change),
url(r'^writedate',writedate),
url(r'^readdate.post',readdate),
)
就是連結與方法的對應配置。

views.py 相當於Java中的那些Controller,各種業務程式碼都在這裡。
顯示部分的程式碼
def backend(request):
    '''進入管理後臺首頁'''
       params = {}
       goodslist=SellingGoods.objects.all()
       params['goodslist'] = goodslist
       c = Context(params)
       return TemplateResponse(request, "jisumai/backend.html", c, content_type)


如此,就可以實現顯示資料的功能了!
為什麼沒有資料庫連線相關程式碼呢?因為資料庫的連線早在settings.py中就已經寫好了。

有這麼清晰簡單的程式碼結構,使用python開發的效率當然很高。


【分頁的實現】
顯示完資料之後,就是將資料分頁顯示。
Python中實現分頁更加簡單,幾乎是安裝零件一樣的。
因為Django提供了一個分頁器類Paginator(django.core.paginator.Paginator),可以很容易的實現分頁的功能。

前端程式碼:
<div id="page" class="page">
{{ goodslist.number }}/{{goodslist.paginator.num_pages }}&nbsp;&nbsp;&nbsp;
   
   {% if goodslist.has_previous %}
   <a href="backend?pageNo={{goodslist.previous_page_number}}" class="w50">上一頁</a>
   {%else%}
   <a class="notFlip w50"><font class="gray">上一頁</font></a>
   {% endif %}
   
   {% autoescape off %}{{pageHtml}}{% endautoescape %}
   &nbsp;&nbsp;&nbsp;
   
   {% if goodslist.has_next %}
   <a class="w50" href="backend?pageNo={{goodslist.next_page_number}}">下一頁</a>
   {%else%}
   <a class="notFlip w50"><font class="gray">下一頁</font></a>
   {% endif %}
</div>


views.py 後端程式碼
from django.core.paginator import Paginator
paginator = Paginator(goodslist, 3)
goodslist = paginator.page(pn)
只需要把這三行程式碼寫進去就可以了。

params = {}
goodslist=SellingGoods.objects.all()
paginator = Paginator(goodslist, 3)
goodslist = paginator.page(pn)
params['goodslist'] = goodslist
其實整體看,就像在返回的goodslist上加了分頁功能似的。

【django工程增刪改查 之 刪】

新增刪除商品的功能。

後端程式碼其實很簡單
def delete(request):
    '''刪除商品操作'''
id = request.GET.get('id')
    p = SellingGoods.objects.get(SELLING_GOODS_ID=id)
    p.delete()
    return HttpResponseRedirect('backend.html')
就是把商品id傳過去。
然後通過id取到那一條資訊,
p.delete()刪除!

【確認對話方塊的使用】
前端涉及到了確認對話方塊的使用:點選刪除連結時,跳出確認刪除對話方塊。

<a href="javascript:void(0)" onclick="javascript:confirm_del({{sellinggoods.SELLING_GOODS_ID}})">刪除</a></td>
function confirm_del(id){
    if(confirm("確認刪除商品"+id+"?")){
        del(id);
    }
}
function del(id){
    window.location.href="delete?id="+id;
}

使用js來實現。確認後通過window.location.href來跳轉,把id帶過去。

【注意關鍵字delete】
寫確認刪除的js時,遇到個問題。
js不生效。
後來發現是js函式名使用了關鍵字delete!要特別注意一下!

【學會除錯js】

關鍵字delete錯誤造成的後果就是js沒有任何反應。

分析這種問題的正確思路應該是:

js沒有反應;js有錯誤或者js相關程式碼有錯誤;除錯js;F12火狐瀏覽器控制檯


觀察js部分有沒有什麼錯誤。然後進入除錯介面

就像這樣,可以開始除錯js。

【django工程增刪改查 之 增】

程式碼如下,按執行順序backend.html
<a href="javascript:void(0)" onclick="javascript:gotoadd()">新增新商品</a><br><br>
function gotoadd(){
    window.open("gotoadd","newwindow","height=450px,width=750px,left=350px,top=200px,menubar=no,status=no,scrollbars=no");
}

views.py
def gotoadd(request):
    '''新增商品對話方塊'''
params={}
    c=Context(params)
    return TemplateResponse(request, "jisumai/add_new_goods.html", c, content_type)

add_new_goods.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>極速賣管理後臺</title>
</head>
<body>
    <center>
    <h3>新增新商品</h3>
    <form action="add" method="post">
    <table border="0" cellpadding="0" cellspacing="0">
    <tr>
      <td align="left" nowrap>商品ID: </td><td align="left" nowrap><input type="text" name="gid"/></td>
    </tr>
    <tr>
      <td align="left" nowrap>商品名稱: </td><td align="left" nowrap><input type="text" name="name" style="width:500px"/></td>
    </tr>
    <tr>
      <td align="left" nowrap>遊戲名稱: </td><td align="left" nowrap><input type="text" name="gamename"/></td>
    </tr>
    <tr>
      <td align="left" nowrap>原價: </td><td align="left" nowrap>
      <input onkeyup="value=value.replace(/[^\d]/g,'') "
onbeforepaste="clipboardData.setData('text',clipboardData.getData('text').replace(/[^\d]/g,''))" type="text" name="oriprice"/></td>
    </tr>
    <tr>
      <td align="left" nowrap>點評: </td>
      <td align="left" nowrap><textarea style= "font-size:10pt;" name="comments"  rows="10" cols="60"></textarea></td>
    </tr>
    <tr>
      <td align="left" nowrap>詳情: </td>
      <td align="left" nowrap><textarea style= "font-size:10pt;" name="details"  rows="2" cols="60"><p><span>遊戲渠道:</span>請在此處輸入賬號型別</p><p><span>伺服器:</span>請在此處輸入伺服器名稱</p></textarea></td>
    </tr>
    <tr>
      <td colspan="2" align="center">
      <input type="submit" name="submit" value="新增"/>
      <input type="reset" name="reset" value="取消"/>
      </td>
    </tr>
  </table>
  </form>
  </center>
</body>
</html>
這裡使用<textarea>標籤能夠預定義輸入框中的內容!
該標籤沒有value屬性!
<textarea>值</textarea>

views.py
def add(request):
    '''新增商品'''
gid = request.POST.get('gid', '')
    name = request.POST.get('name', '')
    gamename = request.POST.get('gamename', '')
    oriprice = request.POST.get('oriprice', '')
    comments = request.POST.get('comments', '')
    details = request.POST.get('details', '')
    if gid=='' or oriprice=='' or name=='' or gamename=='' or comments=='' or details=='':
        params={}
        c=Context(params)
        return TemplateResponse(request, "jisumai/add_error.html", c, content_type)
    a = Goods(SELLING_GOODS_ID=gid, NAME=name, GAME_NAME=gamename, ORI_PRICE=oriprice, COMMENTS=comments, DETAILS=details)
    a.save()
    params={}
    c=Context(params)
    return TemplateResponse(request, "jisumai/add_success.html", c, content_type)
該方法是新增商品的核心方法。
我們可以看到,通過post方式提交的表單內容,先一一拿到。
然後組裝成a,
a.save()。提交到了資料庫!

Java中實現增加的功能,是把拿到的內容賦給一個值,然後層層提交到DAO層,通過增加的SQL語句insert,新增到資料庫。


add_success.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>極速賣管理後臺</title>
</head>
<body>
    <center>
    <h2>新增成功!</h2>
  </center>
</body>
</html>

需要手動關閉跳出來的視窗。

【新增商品頁面視窗】
為了方便使用,把新增頁面做成視窗。
關鍵部分程式碼是:
function gotoadd(){
    window.open("gotoadd","newwindow","height=450px,width=750px,left=350px,top=200px,menubar=no,status=no,scrollbars=no");
}

效果如下: 

這種跳出視窗的方式就是很多新聞入口網站使用的。

選定某些內容可以分享到新浪微博,然後就會跳出這樣的視窗,分享成功後需要自行關閉。

【表單提交 forms.py】

因為涉及到了表單提交,所以後臺程式碼需要寫一個forms.py。

forms.py定義了提交的資料封裝類,即,提交了什麼。

from django.db import models

class Goods(models.Model):
    SELLING_GOODS_ID = models.IntegerField()
    NAME = models.CharField(max_length=100)
    GAME_NAME = models.CharField(max_length=100)
    ORI_PRICE = models.IntegerField()
    COMMENTS = models.CharField(max_length=500)
    DETAILS = models.CharField(max_length=100)

    class Meta:
        db_table = "QUICK_SELLING_GOODS"

然後在views.py中匯入
from moyoyo_zt.jisumai.forms import Goods
具體的add方法中:

【django工程增刪改查 之 改】

依然是跳出對話視窗,然後提交,提示成功後自行關閉。

與增加商品相同的部分不贅述。

流程如下:

views.py

def gotochange(request):
    '''修改商品對話方塊'''
params={}
    id = request.GET.get('id')
    goods=SellingGoods.objects.get(SELLING_GOODS_ID=id)
    params['goods']=goods
    c=Context(params)
    return TemplateResponse(request, "jisumai/change_new_goods.html", c, content_type)

點選修改時把id傳到後臺,取出該條商品的資訊。

change_new_goods.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>極速賣管理後臺</title>
</head>
<body>
    <center>
    <h3>修改商品</h3>
    <form action="change" method="post">
    <table border="0" cellpadding="0" cellspacing="0">
    <tr>
      <td align="left" nowrap>商品ID: </td><td align="left" nowrap><input type="text" name="gid" readonly="true" value="{{goods.SELLING_GOODS_ID}}" /></td>
    </tr>
    <tr>
      <td align="left" nowrap>商品名稱: </td><td align="left" nowrap><input type="text" name="name"  style="width:500px" value="{{goods.NAME}}"/></td>
    </tr>
    <tr>
      <td align="left" nowrap>遊戲名稱: </td><td align="left" nowrap><input type="text" name="gamename" value="{{goods.GAME_NAME}}"/></td>
    </tr>
    <tr>
      <td align="left" nowrap>原價: </td><td align="left" nowrap><input type="text" name="oriprice" value="{{goods.ORI_PRICE}}"/></td>
    </tr>
    <tr>
      <td align="left" nowrap>點評: </td>
      <td align="left" nowrap><textarea style= "font-size:10pt;" name="comments"  rows="10" cols="60" >{{goods.COMMENTS}}</textarea></td>
    </tr>
    <tr>
      <td align="left" nowrap>詳情: </td>
      <td align="left" nowrap><textarea style= "font-size:10pt;" name="details"  rows="2" cols="60">{{goods.DETAILS}}</textarea></td>
    </tr>
    <tr>
      <td colspan="2" align="center">
      <input type="submit" name="submit" value="修改"/>
      </td>
    </tr>
  </table>
  </form>
  </center>
</body>
</html>
顯示該條商品資訊,可以進行修改

views.py

核心方法如下:

def change(request):
    '''修改商品操作'''
gid = request.POST.get('gid')
    p = Goods.objects.get(SELLING_GOODS_ID=gid)
    p.NAME = request.POST.get('name')
    p.GAME_NAME = request.POST.get('gamename')
    p.ORI_PRICE = request.POST.get('oriprice')
    p.COMMENTS = request.POST.get('comments')
    p.DETAILS = request.POST.get('details')
    p.save()
    params={}
    c=Context(params)
    return TemplateResponse(request, "jisumai/change_success.html", c, content_type)
把修改結果提交,直接按id儲存p.save(),就可以成功更新資料庫中的資料。

【django專案中ajax的使用】

需求:

後臺修改活動時間時,

前端的倒計時時間實時變化,


實時變化就是不需要重新整理頁面,能夠更新倒計時的時間。即,需要用到ajax。

實現思路:

把修改時間寫到一個txt檔案中,如event_date.txt。

倒計時隨時通過讀取txt中的  時間字串  來計算。

後臺修改活動時間時,修改的字串更新到這個txt檔案中。

如此,涉及到了txt檔案的讀寫。這個我們寫了很多指令碼之後已經很熟練了。。

實現方法:

1.  把後臺提交的時間寫到txt檔案中

backend.html

活動時間: <input type="text" id="eventdate" name="eventdate" value="{{eventdate}}"> <input type="submit" name="submit" value="修改"/><br><br>
views.py
def writedate(request):
    '''修改活動時間'''
eventdate = request.POST.get('eventdate')
    f=open('C:\\moyoyo_zt\\moyoyo_zt\\jisumai\\event_date.txt', 'w')
    f.write(eventdate)
    f.close()
    return HttpResponseRedirect('backend.html?eventdate='+eventdate)

點選修改按鈕以後,時間已經寫入了event_date.txt。

2. 點選修改以後頁面需要作出的反應

    點選了修改按鈕,頁面重新整理,並把剛剛提交的時間字串顯示在輸入框中。

   【重定向帶引數的注意點】

     重定向到backend.html。意思就是要重走一遍backend方法。

def backend(request):
    '''進入管理後臺首頁'''
pn = request.GET.get("pageNo", "1")
    eventdate = request.GET.get("eventdate", "")
    if eventdate == "":
        f = open('C:\\moyoyo_zt\\moyoyo_zt\\jisumai\\event_date.txt', 'r')
        eventdate=f.readline()
        f.close()
    params = {}
    goodslist=SellingGoods.objects.all()
    paginator = Paginator(goodslist, 3)
    goodslist = pag