python系列学习五——web开发

1. 前言

    一个教练下面有一群学员,教练想把学员的成绩放到web平台上,分享给所有人查看。

2. 设计

    该web应用可能需要3个页面:一个“欢迎”页面,一个“选择选手”页面,以及一个“显示时间”页面

3. 开发

    好的web应用应当遵循MVC模式:

1)模型

建立AthleteList类,将文本数据转换为AthleteList对象实例。新建athletelist.py:

# coding=utf-8

class AthleteList(list):

    def __init__(self, a_name, a_dob=None, a_times=[]):
        list.__init__([])
        self.name = a_name
        self.dob = a_dob
        self.extend(a_times)
    
    @staticmethod
    def sanitize(the_time):
        if '-' in the_time:
            splitter = '-'
        elif ':' in the_time:
            splitter = ':'
        else:
            return the_time
        (mins, secs) = the_time.split(splitter)
        return mins + '.' + secs

    # @property
    def top3(self):
        return sorted(set([self.sanitize(t) for t in self]))[0:3]

新建模块athletemodel.py:

#coding=utf-8

import cPickle as p
from athletelist import AthleteList

def get_coach_data(filename):
    try:
        with open(filename) as f:
            data = f.readline().strip().split(',')
            return AthleteList(data.pop(0), data.pop(0), data)
    except IOError as err:
        print 'File error: ' + str(err)
        return None

def put_to_store(the_files):
    athletes = {}
    for f in the_files:
        ath = get_coach_data(f)
        athletes[ath.name] = ath

    try:
        with open('athletes.pickle' , 'w') as athp:
            p.dump(athletes, athp)
    except IOError as err:
        print 'File error(put_to_store): ' + str(err)
    return athletes

def get_from_store():
    athletes = {}
    try:
        with open('athletes.pickle') as athp:
            athletes = p.load(athp)
    except IOError as err:
        print 'File erro(get_from_store): ' + str(err)
    return athletes

2)视图

模板引擎yate.py

#coding=utf-8
"""从标准库的'string'模块导入'Template'类,它支持简单的字符串替换模板"""
from string import Template

# 该函数需要一个(可选)字符串作为参数,用来创建一个CGI行,默认值是:"text/html"
def start_response(resp="text/html"):
    return('Content-type: ' + resp + '\n\n')

def include_header(the_title):
    # 打开模板文件,读入文件内容,换入所提供的标题
    with open('templates/header.html') as headf:
        head_text = headf.read()
    header = Template(head_text)
    #subsitute()方法用来替换字符串中指定内容
    return(header.substitute(title=the_title))

def include_footer(the_links):
    with open('templates/footer.html') as footf:
        foot_text = footf.read()
    # 将链接字典转换为一个字符串,再换入模板
    link_string = ''
    for key in the_links:
        link_string += '<a href="' + the_links[key] + '">' + key + '</a>    '
    footer = Template(foot_text)
    return(footer.substitute(links=link_string))

#返回表单最前面的html,允许指定url和type
def start_form(the_url, form_type="POST"):
    return('<form action="' + the_url + '" method="' + form_type + '">')

# 返回表单末尾的html,允许定制submit的文本内容
def end_form(submit_msg="Submit"):
    return('<p></p><input type=submit value="' + submit_msg + '"></form>')

# 给定一个单选按钮名和值,创建一个html单选组
def radio_button(rb_name, rb_value):
    return('<input type="radio" name="' + rb_name +
                             '" value="' + rb_value + '"> ' + rb_value + '<br />')

# 给定一个项列表,函数将该列表转换为一个html无序列表。每次迭代增加一个li元素
def u_list(items):
    u_string = '<ul>'
    for item in items:
        u_string += '<li>' + item + '</li>'
    u_string += '</ul>'
    return(u_string)

# 创建并返回一个html标题标记,默认为2级标题
def header(header_text, header_level=2):
    return('<h' + str(header_level) + '>' + header_text +
           '</h' + str(header_level) + '>')

# 用html段落标记创建一个文本段
def para(para_text):
    return('<p>' + para_text + '</p>') 

3)用python构建一个web服务器

新建模块simple_httpd.py

#!/usr/local/bin/python
#coding=utf-8

# 导入http服务器和CGI模块
from BaseHTTPServer import HTTPServer
from CGIHTTPServer import CGIHTTPRequestHandler

#指定一个端口 
port = 8080

#创建一个http服务器
httpd = HTTPServer(('', port), CGIHTTPRequestHandler)

#显示一个友好消息,并启动服务器
print("Starting simple_httpd on port: " + str(httpd.server_port))
httpd.serve_forever()
在终端执行该模块:


打开浏览器,在地址栏输入 http://localhost:8080,可直接进入webapp下的index.html页面。

同时,web服务器记录了web请求的运行日志:


4) 控制器

    推荐web应用目录结构

    webapp/                                     项目顶层文件夹,除了包含子文件夹,还包含web应用的index.html、favicon.ico、样式表以及不放在其他子文件夹的所有内容

                  cgi-bin/                         为web应用写的所有代码需要放在一个名为cgin-bin的文件夹中

                  data/                              存放数据的文件夹

                  images/                        存放web应用的图像文件

                  templates/                    存放web应用的模板文件


在cgi-bin目录中,新建选择选手页面generate_list.py:

#!/usr/local/bin/python
#coding=utf-8

import athletemodel
import yate
import glob

data_files = glob.glob('data/*.txt')
athletes = athletemodel.put_to_store(data_files)

# genereate form 
print yate.start_response()
print yate.include_header("Coach Kelly's list of Athletes")
print yate.start_form("generate_timing_data.py")
print yate.para("Select an athlete from the list to work with:")
for item in athletes:
    print yate.radio_button('athlete', athletes[item].name)
print yate.end_form('Selete')

print yate.include_footer({"Home":"/index.html"})

再建立显示时间页面generate_timing_data.py

#!/usr/local/bin/python
#coding=utf-8

import cgi
import athletemodel
import yate
import cgitb
cgitb.enable()

# get all form data, and store a dictionary
form_data = cgi.FieldStorage()
# access a specify data from form data
athlete_name = form_data['athlete'].value

athletes = athletemodel.get_from_store()
print yate.start_response()
print yate.include_header("Coach Kelly's Timing Data")
print yate.header("Athlete: " + athlete_name + ", DOB: "+ athletes[athlete_name].dob + ".")
print yate.para("The top times for this athlete are: ")
print yate.u_list(athletes[athlete_name].top3())    #如果top3()方法被指定为@property,访问时直接使用.top3
print yate.include_footer({"Home":"/index.html", 
                            "Select another athlete": "generate_list.py"})

4. 调试

python标准库提供了一个CGI跟踪模块cgitb,弃用这个模块时,会在web浏览器上显示详细的错误消息。

在CGI脚本前面增加下面两行代码,启用python的CGI跟踪技术:

import cgitb
cgitb.enable()


小结:

1)标准库string模块包括一个名为Template的类,它支持简单的字符串替换

2)标准库BaseHTTPServer、CGIHTTPServer(3.x版本合并为http.server)模块可以在python中建立一个简单的web服务器

3)标准库glob模块适合处理文件名列表

4)启用标准库cgitb时,允许在浏览器中查看CGI编码错误

5)使用cgi.FieldStorage()访问作为web请求发送给web服务器的数据,数据将作为一个python字典

6)@property修饰符,可以使类的方法表现的像是一个属性

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值