在初识Bottle(一)中,我们了解了Bottle的基本用法
在Bottle源码阅读(一)和Bottle源码阅读(二)可以查看个人对bottle源码的相关阅读笔记
下面继续阅读Bottle的官方文档https://bottlepy.org/docs/dev…
1.路由静态文件
在bottle中例如css等的文件是不会被自动加载的,因此需要自己定义callback函数,通过调用使用
from bottle import static_file
@route('/static/<filename>')
def server_static(filename):
return static_file(filename, root='/path/to/your/static/files')
2.错误页
通过error装饰器可以对相应的错误码自定义对应的应用函数
from bottle import error
@error(404)
def error404(error):
return 'Nothing here, sorry'
3.内容返回
Bottl框架允许应用函数返回如下类型的结果
Dictionaries字典:
python的字典通过框架被转换为json字符串,而header中的Content-Type则会被设置为application/json
Empty Strings, False, None or other non-true values:
header中的Content-Length被设置为0
Unicode strings
Byte strings
Instances of HTTPError or HTTPResponse
File objects
Iterables and generators
4.改变默认编码
通过在应用函数中改变response的属性可以自定义
from bottle import response
@route('/iso')
def get_iso():
response.charset = 'ISO-8859-15'
return u'This will be sent with ISO-8859-15 encoding.'
@route('/latin9')
def get_latin():
response.content_type = 'text/html; charset=latin9'
return u'ISO-8859-15 is also known as latin9.'
5.静态文件的使用
通过static_file接口,我们可以实现调用和下载
from bottle import static_file
@route('/images/<filename:re:.*\.png>')
def send_image(filename):
return static_file(filename, root='/path/to/image/files', mimetype='image/png')
@route('/static/<filename:path>')
def send_static(filename):
return static_file(filename, root='/path/to/static/files')
@route('/download/<filename:path>')
def download(filename):
return static_file(filename, root='/path/to/static/files', download=filename)
6.HTTP ERRORS AND REDIRECTS
通过abort可以快速定义错误码相应的错误页内容
redirect实现重定向
from bottle import route, abort
@route('/restricted')
def restricted():
abort(401, "Sorry, access denied.")
from bottle import redirect
@route('/wrong/url')
def wrong():
redirect("/right/url")
7.RESPONSE
response对象包括了响应的metadata例如状态码,headers,cookie等
response的状态码控制浏览器的行为,默认200ok
response的header可以通过set_header()来设置,对同一个header项,还可以通过add_header添加额外内容
cookie是保留在用户浏览器的一些数据,可以通过get_cookie和set_cookie来操作
@route('/hello')
def hello_again():
if request.get_cookie("visited"):
return "Welcome back! Nice to see you again"
else:
response.set_cookie("visited", "yes")
return "Hello there! Nice to meet you"
cookie是容易被伪造的,所以Bottle框架提供了cookie的签名机制,只需要提供一个secret的参数作为密钥
Bottle会自动持久化和去持久化保存在cookie中的数据,cookie不超过4k。
此时cookie仍然能从浏览器中查看到,而且是可以被复制的,所以最好不要将密钥的信息放在用户客户端
@route('/login')
def do_login():
username = request.forms.get('username')
password = request.forms.get('password')
if check_login(username, password):
response.set_cookie("account", username, secret='some-secret-key')
return template("<p>Welcome {{name}}! You are now logged in.</p>", name=username)
else:
return "<p>Login failed.</p>"
@route('/restricted')
def restricted_area():
username = request.get_cookie("account", secret='some-secret-key')
if username:
return template("Hello {{name}}. Welcome back.", name=username)
else:
return "You are not logged in. Access denied."
8.REQUEST
request 对象包括了Cookies, HTTP header, HTML <form>等一系列可以操作的对象
from bottle import request, route, template
@route('/hello')
def hello():
name = request.cookies.username or 'Guest'
return template('Hello {{name}}', name=name)
Bottle使用FormsDict存储表单数据和cookie数据,而FormsDict的特定就是既具备了普通字典的操作方法,又能将key作为对象的属性,具体如下name既是字典的key又是cookies的属性
name = request.cookies.name
# is a shortcut for:
name = request.cookies.getunicode('name') # encoding='utf-8' (default)
# which basically does this:
try:
name = request.cookies.get('name', '').decode('utf-8')
except UnicodeError:
name = u''
同时,FormsDict还能对单个key存储多个值
for choice in request.forms.getall('multiple_choice'):
do_something(choice)
request的query string会被分解为多个键值对,而通过request.query可以直接获得查询字符串对应键的值
from bottle import route, request, response, template
@route('/forum')
def display_forum():
forum_id = request.query.id
page = request.query.page or '1'
return template('Forum ID: {{id}} (page {{page}})', id=forum_id, page=page)
上传文件时,我们需要在表单添加enctype=”multipart/form-data”, 同时将type设置为file
<form action="/upload" method="post" enctype="multipart/form-data">
Category: <input type="text" name="category" />
Select a file: <input type="file" name="upload" />
<input type="submit" value="Start upload" />
</form>
文件上传到服务端后
@route('/upload', method='POST')
def do_upload():
category = request.forms.get('category')
upload = request.files.get('upload')
name, ext = os.path.splitext(upload.filename)
if ext not in ('.png','.jpg','.jpeg'):
return 'File extension not allowed.'
save_path = get_save_path_for_category(category)
upload.save(save_path) # appends upload.filename automatically
return 'OK'
通过BaseRequest.body我们可以直接获取原始的请求体,也可以获取environ
@route('/my_ip')
def show_ip():
ip = request.environ.get('REMOTE_ADDR')
# or ip = request.get('REMOTE_ADDR')
# or ip = request['REMOTE_ADDR']
return template("Your IP is: {{ip}}", ip=ip)
9.模板
Bottle内建了前端模板引擎,在官网给出的这个例子中,会加载./views/中的hello_template.tpl
@route('/hello')
@route('/hello/<name>')
def hello(name='World'):
return template('hello_template', name=name)
或者
@route('/hello')
@route('/hello/<name>')
@view('hello_template')
def hello(name='World'):
return dict(name=name)
%if name == 'World':
<h1>Hello {{name}}!</h1>
<p>This is a test.</p>
%else:
<h1>Hello {{name.title()}}!</h1>
<p>How are you?</p>
%end
模板在编译后会被缓存到内存中,修改后需要执行bottle.TEMPLATES.clear()清除缓存模板
10.PLUGINS
Bottle提供了一系列的第三方引擎,这些能够有效地减少重复性工作
官网使用SQLitePlugin作为例子,在每一次调用需要与数据库进行交互的callback函数时,该引擎会自动创建连接和关闭连接。而其他的引擎,例如’auth‘能够帮我们进行验证登录
from bottle import route, install, template
from bottle_sqlite import SQLitePlugin
install(SQLitePlugin(dbfile='/tmp/test.db'))
@route('/show/<post_id:int>')
def show(db, post_id):
c = db.execute('SELECT title, content FROM posts WHERE id = ?', (post_id,))
row = c.fetchone()
return template('show_post', title=row['title'], text=row['content'])
@route('/contact')
def contact_page():
''' This callback does not need a db connection. Because the 'db'
keyword argument is missing, the sqlite plugin ignores this callback
completely. '''
return template('contact')
sqlite_plugin = SQLitePlugin(dbfile='/tmp/test.db')
install(sqlite_plugin)
uninstall(sqlite_plugin) # uninstall a specific plugin
uninstall(SQLitePlugin) # uninstall all plugins of that type
uninstall('sqlite') # uninstall all plugins with that name
uninstall(True) # uninstall all plugins at once
自此,Bottle官网的tutorial我们已经大致有了了解
后续我们可以选择运用该框架实现一些简单的应用,或者可以深入研究其源码,提升自身的编程水平