使用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)
ENGINE=INNODB DEFAULT CHARSET=utf8;
指定编码格式
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的非空属性改了。
width=1000 height=500 border="1">
bgcolor="lightgrey" height=10>
width=150>商品ID
width=500>商品名称
width=100>游戏名称
width=100>原价
width=150>操作
{% for sellinggoods in goodslist %}
{{sellinggoods.SELLING_GOODS_ID}}
{{sellinggoods.NAME}}
{{sellinggoods.GAME_NAME}}
{{sellinggoods.ORI_PRICE}}
href="javascript:void(0)" οnclick="javascript:gotochange({{sellinggoods.SELLING_GOODS_ID}})">修改
href="javascript:void(0)" οnclick="javascript:confirm_del({{sellinggoods.SELLING_GOODS_ID}})">删除
{% endfor %}
用一个table来显示所有内容。
{% for sellinggoods in goodslist %}
{{sellinggoods.SELLING_GOODS_ID}}
{% endfor %}
回顾一下Java中的这部分代码
${message.username}
${message.content}
${message.reply}
使用的是forEach标签。
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"
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), )就是链接与方法的对应配置。
def backend(request): '''进入管理后台首页'''
params = {} goodslist=SellingGoods.objects.all()
params['goodslist'] = goodslist
c = Context(params) return TemplateResponse(request, "jisumai/backend.html", c, content_type)
id="page" class="page">
第{{ goodslist.number }}页/共{{goodslist.paginator.num_pages }}页
{% if goodslist.has_previous %}
href="backend?pageNo={{goodslist.previous_page_number}}" class="w50">上一页
{%else%}
class="notFlip w50">class="gray">上一页
{% endif %}
{% autoescape off %}{{pageHtml}}{% endautoescape %}
{% if goodslist.has_next %}
class="w50" href="backend?pageNo={{goodslist.next_page_number}}">下一页
{%else%}
class="notFlip w50">class="gray">下一页
{% endif %}
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传过去。
href="javascript:void(0)" οnclick="javascript:confirm_del({{sellinggoods.SELLING_GOODS_ID}})">删除
function confirm_del(id){ if(confirm("确认删除商品"+id+"吗?")){ del(id); } } function del(id){ window.location.href="delete?id="+id; }
【学会调试js】
关键字delete错误造成的后果就是js没有任何反应。
分析这种问题的正确思路应该是:
js没有反应;js有错误或者js相关代码有错误;调试js;F12火狐浏览器控制台
观察js部分有没有什么错误。然后进入调试界面
就像这样,可以开始调试js。
【django工程增删改查 之 增】
href="javascript:void(0)" οnclick="javascript:gotoadd()">添加新商品
function gotoadd(){ window.open("gotoadd","newwindow","height=450px,width=750px,left=350px,top=200px,menubar=no,status=no,scrollbars=no"); }
def gotoadd(request): '''添加商品对话框''' params={} c=Context(params) return TemplateResponse(request, "jisumai/add_new_goods.html", c, content_type)
html>
lang="en">
charset="UTF-8">
极速卖管理后台
添加新商品
这里使用
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)该方法是添加商品的核心方法。
html>
lang="en">
charset="UTF-8">
极速卖管理后台
添加成功!
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"
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
html>
lang="en">
charset="UTF-8">
极速卖管理后台
修改商品
显示该条商品信息,可以进行修改
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
活动时间: type="text" id="eventdate" name="eventdate" value="{{eventdate}}"> type="submit" name="submit" value="修改"/>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设置输入框为只读属性】
修改商品时,我们不希望修改某些数值的时候,可以把输入框的属性设置为只读。
type="text" name="gid" readonly="true" value="{{goods.SELLING_GOODS_ID}}" />
即,readonly属性。
【日期控件的使用】
效果图如下:
即输入时间字符串时,通过点击控件日历来输入,用户不需要自己敲字儿了。。
实现方法:
backend.html中,
引入如下css和js
rel="stylesheet" type="text/css" media="all" href="http://res.moyoyo.com/upload/jisumai/css/calendar-miles.css" title="win2k-cold-1" />
写入如下js:
js中指定了inputField为eventdate,即
活动时间: type="text" id="eventdate" name="eventdate" value="{{eventdate}}">是id还是name呢?
应该是id吧。
如此,就可以顺利使用日期控件了。