【詳解】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> <a href="javascript:void(0)" onclick="javascript:gotochange({{sellinggoods.SELLING_GOODS_ID}})">修改</a> <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 }}頁 {% 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 %} {% 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工程增刪改查 之 增】
<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