您的位置:首页 > 编程语言 > Python开发

【详解】Python专题开发

2016-02-17 17:47 751 查看
使用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工程增删改查 之 增】


代码如下,按执行顺序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 = paginator.page(pn)
params['goodslist'] = goodslist
params['eventdate'] = eventdate
c = Context(params)
return TemplateResponse(request, "jisumai/backend.html", c, content_type)

从该方法中我们可以看到,

如果eventdate输入框中没有数值时,就去读取txt文件中的值然后写入

如果修改eventdate,即输入框中原来有一个值时,直接把这个新值  重新提交到html就可以了。

之前遇到过的问题是writedate方法中最后的重定向链接带参数,无法在后台首页显示修改后的时间字符串。

原因就是虽然提交到了html页面,但是没有走backend方法,所以才不显示的。

也就是说,前台页面的数据显示,都需要后台来进行支持。每一个数据都是,如果没有后台的支持,前台就只是死的页面,

不会有数据的更新变化。

3.ajax的实现方法

   直接上代码

   index.html中的js代码

window.setInterval(
function(){
$.ajax({
type: "POST",
url: "readdate.post",
data:"",
success: function(data) {
var y=data.split('-')[0]
var m=data.split('-')[1]
var d=data.split('-')[2]
ShowCountDown(y,m,d,'divdown1');
}
});
},
interval);//倒计时结束日期
     views.py中的读取方法

def readdate(request):
'''读取活动时间'''
f=open('C:\\moyoyo_zt\\moyoyo_zt\\jisumai\\event_date.txt', 'r')
eventdate=f.readline()
f.close()
return HttpResponse(eventdate)

    urls.py中配置



这样就成功使用ajax实现了倒计时的实时更新。

【Python中文件的绝对路径】

应当是这样的

C:\\moyoyo_zt\\moyoyo_zt\\jisumai\\event_date.txt

双反斜杠。

【HTML设置输入框为只读属性】

修改商品时,我们不希望修改某些数值的时候,可以把输入框的属性设置为只读。

<input type="text" name="gid" readonly="true" value="{{goods.SELLING_GOODS_ID}}" />

即,readonly属性。

【日期控件的使用】

效果图如下:



即输入时间字符串时,通过点击控件日历来输入,用户不需要自己敲字儿了。。

实现方法:

backend.html中,


引入如下css和js

<link rel="stylesheet" type="text/css" media="all" href="http://res.moyoyo.com/upload/jisumai/css/calendar-miles.css" title="win2k-cold-1" />
<script type="text/javascript" src="http://res.moyoyo.com/upload/jisumai/js/calendar.js"></script>
<script type="text/javascript" src="http://res.moyoyo.com/upload/jisumai/js/calendar-zh.js"></script>
<script type="text/javascript" src="http://res.moyoyo.com/upload/jisumai/js/calendar-setup.js"></script>


写入如下js:

<script type="text/javascript">
function noop() {}
Calendar.setup({
inputField     :    "eventdate",
ifFormat       :    "%Y-%m-%d",
showsTime      :    true,
timeFormat     :    "24",
onUpdate       :    noop
});
</script>
js中指定了inputField为eventdate,即

活动时间: <input type="text" id="eventdate" name="eventdate" value="{{eventdate}}">

是id还是name呢?

应该是id吧。

如此,就可以顺利使用日期控件了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: