一、构建一个Web应用
除了已经掌握的python知识,要构建一个实际运行的服务器端Web应用,还需要了解Web应用框架,它提供了一组通用的基础技术,可以基于这些技术构建你的Web应用,在这里,我们直接选择一个名为Flask的流行框架
安装Flask
windows上,打开一个命令行提示窗口,一定要作为管理员运行,执行下面的命令:
py -3 -m pip install flask
在Mac OS或Linux上,在一个终端窗口键入以下命令:
sudo -H python3 -m pip install flask
检查Flask是否已经安装并正常运行
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello() -> str:
return 'Hello world from Flask!'
app.run()
保存这段程序命名为hello_flask.py
在windows命令窗口下运行这段程序:
py -3 hello_flask.py
在浏览器中输入127.0.0.1:5000,若显示Hello world from Flask!则运行成功啦
构建HTML表单,为Web提供功能
具体的HTML代码和css样式,
戳这儿:https://github.com/wentaoStyle/HeadFirstPython/tree/master/ch4
from flask import Flask, render_template, request
from vsearch import search4letters
app = Flask(__name__)
@app.route('/search4', methods=['POST'])
def do_search() -> 'html':
phrase = request.form['phrase']
letters = request.form['letters']
title = 'Here are your results:'
results = str(search4letters(phrase, letters))
return render_template('results.html',
the_title=title,
the_phrase=phrase,
the_letters=letters,
the_results=results,)
@app.route('/')
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
if __name__ == '__main__':
app.run(debug=True)
小插曲:
HTTP的5类状态码:
100-199范围内的状态码是信息消息,这些状态码都没有问题,服务器在提供关于客户端请求的详细信息
200-299范围内的状态码是成功消息:服务器已经接收、理解和处理客户端的请求。一切正常。
300-399范围内的状态码是重定向消息:服务器通知客户端请求在别处处理。
400-499范围内的状态码是客户端错误消息:服务器从客户端接收到一个他不理解也无法处理的请求。通常这是客户端的问题。
500-599范围内的状态码是服务器端错误消息:服务器从客户端接收一个请求,但是服务器尝试处理这个请求时失败了。通常这是服务器的问题。
二、存储和管理数据
python支持打开、处理和关闭文件
todos = open('todos.txt','a')
print('day day up',file=todos)
todos.close()
tasks = open('todos.txt')
for chore in tasks:
print(chore,end='')
tasks.close()
with open ('todos.txt') as tasks:
for chore in tasks:
print(chore,end='')
with语句用于管理上下文
names = ['l','o','v','e']
python = '|'.join(names)
individuals = pythons.split('|')
from flask import Flask, render_template, request, escape
from vsearch import search4letters
app = Flask(__name__)
def log_request(req: 'flask_request', res: str) -> None:
with open('vsearch.log', 'a') as log:
print(req.form, req.remote_addr, req.user_agent, res, file=log, sep='|')
@app.route('/search4', methods=['POST'])
def do_search() -> 'html':
phrase = request.form['phrase']
letters = request.form['letters']
title = 'Here are your results:'
results = str(search4letters(phrase, letters))
log_request(request, results)
return render_template('results.html',
the_title=title,
the_phrase=phrase,
the_letters=letters,
the_results=results,)
@app.route('/')
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
@app.route('/viewlog')
def view_the_log() -> 'html':
contents = []
with open('vsearch.log') as log:
for line in log:
contents.append([])
for item in line.split('|'):
contents[-1].append(escape(item))
titles = ('Form Data', 'Remote_addr', 'User_agent', 'Results')
return render_template('viewlog.html',
the_title='View Log',
the_row_titles=titles,
the_data=contents,)
if __name__ == '__main__':
app.run(debug=True)
三、使用数据库
1、安装MySQL服务器
http://dev.mysql.com/downloads/mysql/
2.为python安装一个MySQL数据库驱动程序
http://dev.mysql.com/downloads/connector/python/
3.安装MySQL Connector/Python
py -3 setup.py install
def log_request(req: 'flask_request', res: str) -> None:
dbconfig = {'host':'127.0.0.1',
'user':'vsearch',
'password':'vsearchpasswd',
'database':'vsearchlogdb',}#定义连接属性
import mysql.connector#导入数据库驱动程序
conn = mysql.connector.connect(**dbconfig)#建立与服务器的一个链接
cursor = conn.cursor()#创建一个游标来想服务器发送命令以及接收结果
_SQL = """insert into log(phrase,letters,ip,browser_string,results) values
(%s,%s,%s,%s,%s)"""#将查询赋至一个字符串
cursor.execute(_SQL,(req.form['phrase'],
req.form['letters'],
req.remote_addr,
req.user_agent.browser,
res,))#将查询发送到服务器
conn.commit()#强制 要求数据库写数据
cursor.close()
conn.close()
五、一点点类
class CountFromBy:
def __init__(self, v:int=0, i:int=1) -> None:
self.val = v
self.incr = i
def increase(self) -> None:
self.val += self.incr
def __repr__(self) -> str:
return str(self.val)
class关键字在代码中引入一个新类
从类创建一个对象看上去非常类似于一个函数调用。
mycount = CountFromBy()
上下文管理协议
import mysql.connector
class UseDatabase:
def __init__(self, config: dict):
self.configuration = config
def __enter__(self) -> 'cursor':
self.conn = mysql.connector.connect(**self.configuration)
self.cursor = self.conn.cursor()
return self.cursor
def __exit__(self, exc_type, exc_value, exc_traceback):
self.conn.commit()
self.cursor.close()
self.conn.close()
with UseDatabase(app.config['dbconfig']) as cursor:
_SQL = """select phrase, letters, ip, browser_string, results
from log"""
cursor.execute(_SQL)
contents = cursor.fetchall()
六、函数修饰符
1.函数修饰符是一个函数
2.修饰符取被修饰符为参数
3.修饰符返回一个新函数
4.修饰符维护被修饰函数的签名
创建你自己的修饰符时,一定要导入并使用“functools”模块的"wraps"函数
from flask import session
from functools import wraps
def check_logged_in(func):
@wraps(func)
def wrapper(*args, **kwargs):
if 'logged_in' in session:
return func(*args, **kwargs)
return 'You are NOT logged in.'
return wrapper
七、异常处理
try:
with open('myfile.txt') as fh:
file_data = fh.read()
print(file_data)
except FileNotFoundError:
print('The data file is missing.')
except PermissionError:
print('This is not allowed.')
except Exception as err:
print('Some other error occurred:', str(err))
八、线程
要创建一个线程,你要创建一个Thread对象,将一个名为target的参数指定为你希望这个线程执行的函数名,并为另一个名为args的命名参数提供其他参数(作为一个元组)。再把创建的Thread对象赋给你选择的变量。
from threading import Thread
t = Thread(target=func,arges=())
t.start()
from flask import Flask, render_template, request, escape, session
from vsearch import search4letters
from DBcm import UseDatabase, ConnectionError, CredentialsError, SQLError
from checker import check_logged_in
from threading import Thread
from time import sleep
app = Flask(__name__)
app.config['dbconfig'] = {'host': '127.0.0.1',
'user': 'vsearch',
'password': 'vsearchpasswd',
'database': 'vsearchlogdb', }
@app.route('/login')
def do_login() -> str:
session['logged_in'] = True
return 'You are now logged in.'
@app.route('/logout')
def do_logout() -> str:
session.pop('logged_in')
return 'You are now logged out.'
def log_request(req: 'flask_request', res: str) -> None:
sleep(15) #sleep
with UseDatabase(app.config['dbconfig']) as cursor:
_SQL = """insert into log
(phrase, letters, ip, browser_string, results)
values
(%s, %s, %s, %s, %s)"""
cursor.execute(_SQL, (req.form['phrase'],
req.form['letters'],
req.remote_addr,
req.user_agent.browser,
res, ))
@app.route('/search4', methods=['POST'])
def do_search() -> 'html':
phrase = request.form['phrase']
letters = request.form['letters']
title = 'Here are your results:'
results = str(search4letters(phrase, letters))
try:
t = Thread(target=log_request, args=(request, results))
t.start()
except Exception as err:
print('***** Logging failed with this error:', str(err))
return render_template('results.html',
the_title=title,
the_phrase=phrase,
the_letters=letters,
the_results=results,)
@app.route('/')
@app.route('/entry')
def entry_page() -> 'html':
return render_template('entry.html',
the_title='Welcome to search4letters on the web!')
@app.route('/viewlog')
@check_logged_in
def view_the_log() -> 'html':
try:
with UseDatabase(app.config['dbconfig']) as cursor:
_SQL = """select phrase, letters, ip, browser_string, results
from log"""
cursor.execute(_SQL)
contents = cursor.fetchall()
titles = ('Phrase', 'Letters', 'Remote_addr', 'User_agent', 'Results')
return render_template('viewlog.html',
the_title='View Log',
the_row_titles=titles,
the_data=contents,)
except ConnectionError as err:
print('Is your database switched on? Error:', str(err))
except CredentialsError as err:
print('User-id/Password issues. Error:', str(err))
except SQLError as err:
print('Is your query correct? Error:', str(err))
except Exception as err:
print('Something went wrong:', str(err))
return 'Error'
app.secret_key = 'YouWillNeverGuessMySecretKey'
if __name__ == '__main__':
app.run(debug=True)
九、高级迭代
推导式比等价的for循环代码执行的更快
列表推导式
destinations = []
for dest in flights.values():
destinations.append(dest.title())
more_dests = [dest.title() for dest in flights.value()]
字典推导式:
just = {}
for k,v in flights.items():
if v == 'FREEPORT':
just[covert2ampm(k)] = v.title()
just2 = {covert2ampm(k):v.title() for k,v in flights.items() if v== 'FREEPORT'}
集合推导式
found = set()
for v invowels:
if v in message:
found.add(v)
found2 = { v for v in vowels if v in message}
使用列表推导式的地方都可以使用生成器,会生成同样的结果
for i in (x*3 for x in [1,2,3,4,5]):
print(i)
生成器一次生成一个数据项,使用生成器的徐变换响应性更好,而使用列表推导式的循环会让你等待
列表推导式是用中括号包围的代码,字典推导是是用大括号包围的代码(有冒号分隔符),集合推导式也是用大括号包围的代码(但没有字典推导式的冒号)
如果发现推导式代码用小括号包围,你看到的是一个生成器(可以装换为一个函数,使用yield根据需要生成数据)
from datetime import datetime
import pprint
def convert2ampm(time24: str) -> str:
return datetime.strptime(time24, '%H:%M').strftime('%I:%M%p')
with open('buzzers.csv') as data:
ignore = data.readline()
flights = {}
for line in data:
k, v = line.strip().split(',')
flights[k] = v
pprint.pprint(flights)
print()
fts = {convert2ampm(k): v.title() for k, v in flights.items()}
pprint.pprint(fts)
print()
when = {dest: [k for k, v in fts.items() if v == dest] for dest in set(fts.values())}
pprint.pprint(when)
print()
在这里插入代码片