Notas de estudio de botella
- 1. Medio ambiente
- 2. Puntos de conocimiento
-
- 2.1 Marco
- 2.2 Decorador de URL
- 2.3 404 y redirección de URL
- 2.4 Obtener parámetros de solicitud de obtención y publicación
- 2.5 Devolver diferentes tipos de datos para clientes web
- 2.6 Usar cookies y cookies firmadas para rastrear clientes
- 2.7 Carga y recepción de archivos HTTP
- 2.8 Motor de plantillas incorporado
- 2.9 Implementación del programa del sitio web de Bottle
- 2.10 Registro de usuario e inicio de sesión
Las notas se colocan en el almacén: https://github.com/Turing-dz/bottle_study_notes
1. Medio ambiente
Abrir cmd como administrador
conda create -n bottle python
conda activate bottle
pip install bottle
2. Puntos de conocimiento
2.1 Marco
1. El programa servidor con menos código
from bottle import run,route
@route('/')
def index():
return "I am bottle"
run(host="localhost",port="80",debug=True,deloader=True)
2. Use un marco de programa de servidor orientado a objetos
from bottle import Bottle,run
web=Bottle()
@web.route("/")
def index():
return "I am bottle2"
run(web)
El servidor ejecuta la ejecución de la función, especificando la dirección IP y el puerto (host, puerto) del servidor; muestra información de depuración (depuración); reinicia automáticamente el servicio después de la modificación del código (descargador)
2.2 Decorador de URL
1. La respuesta predeterminada a la solicitud de obtención, puede definir el método para responder a una variedad de métodos de solicitud, request.method para determinar el método de solicitud
from bottle import route, run ,request,get,post
htmlstr="""
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>BOTTLE</title>
</head>
<body>
<form action ="/demo_gp" method="POST">
<input type="submit"/>
</form>
</body>
</html>
"""
@route("/")
def index():
return htmlstr
@route("/demo_post",method="POST")#1.响应post请求
def pt():
return "receive method post"
#@route("/demo_gp",method=["POST","GET"])#2.响应两种请求方式
@get("/demo_gp")#3.响应两种请求方法
@post("/demo_gp")
def gp():
if request.method=="GET":#request.method判断请求的方式
return htmlstr
else:
return "this is post"
run()
2. Enrutamiento dinámico
from bottle import route,run ,Bottle
import re
@route("/hello/<name>")#1.路由传递字符串
def index(name=""):
return "Hello %s"%name
@route("/uid/<uid:int>")#2.路由传递整型
def getuid(uid=0):
return "your id is %d"%uid
@route("/weight/<weight:float>")#3.路由传递浮点数
def getweight(weight):
return "your weight:%f"%weight
@route("/getfilepath/<file_path:path>")#4.路由传递路径
def getpath(file_path):
return file_path
@route("/rege/<ret:re:[0-1]*>")#5.正则匹配路由传递的参数
def rege(ret):
return ret
#6.自定义路由过滤器
app=Bottle()
def list_filter(config):
delimiter=config or ","
regexp=r'\d+(%s\d)*'%re.escape(delimiter)
def to_python(match):
return map(int,match.split(delimiter))
def to_url(numbers):
return delimiter.join(map(str,numbers))
return regexp,to_python,to_url
app.router.add_filter('idslist',list_filter)
@app.route("/hello/<ids:idslist>")
def hello(ids):
res=''
for i in ids:
res+=str(i)+'-'
return "hello %s"%res
run(app,port=80,debug=True)
2.3 404 y redirección de URL
from bottle import route,run,static_file,error,abort,redirect
#1.返回静态文件内容return static_file(filename,root="静态文件地址",mimetype="静态文件类型")
@route("/static/<filename:path>")
def index(filename):
return static_file(filename,root="",download=True)
#2.强制下载文件,return static_file(filename,root="",download=True/"yourfilename")
@route("/dl/<filename:path>")
def dl(filename):
return static_file(filename,root='',download="sd.jpg")
#3.指定404页面
@error(404)
def err(err):
return "页面丢失"
#4.url转向:转向错误abort(404,"error_info"),调用redirect("other url")
@route("/abort")
def ab():
abort(404,"转向丢失页面")##4.1转向丢失页面
##4.2转向指定页面
@route("/")
def index():
return "登录成功"
@route("/login/<name>")###登陆成功转向/目录,失败就转向login,且页面丢失
def login(name):
if name =="abc":
redirect("/")
else:
redirect("/login")
run(port="80",debug=True,reloader=True)
2.4 Obtener parámetros de solicitud de obtención y publicación
1. Obtenga la provisión de parámetros: enlace de URL agregue "? nombre = valor & nombre = valor..."
obtenga adquisición de parámetros: solicitud.consulta.nombre (cuando el nombre no existe, devuelva una cadena vacía)
from bottle import route, run ,request,get,post
htmlstr="""
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>BOTTLE</title>
</head>
<body>
<form action ="/get_to">
<label>姓名</label>
<input type="text" name="name"/>
<label>电话号码</label>
<input type="text" name="telephone"/>
<label>邮箱</label>
<input type="text" name="email"/>
<input type="submit"/>
</form>
<a href="http://127.0.0.1:8080/get_to?name=1&telephone=2&email=3">提交get信息</a>
</body>
</html>
"""
@route("/")
def index():
return htmlstr
@route("/get_to")
def getto():
name=request.query.name#获取
telephone=request.query.telephone
email=request.query.email
return (name,telephone,email)
run(debug=True,reloader=True)
2. Disposición del parámetro de publicación: agregue method="post" al formulario enviado
Obtenga el parámetro de publicación: request.forms.get("name")
from bottle import route, run ,request,get,post
htmlstr="""
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>BOTTLE</title>
</head>
<body>
<form action ="/post_to" method="POST">
<label>姓名</label>
<input type="text" name="name"/>
<label>电话号码</label>
<input type="text" name="telephone"/>
<label>邮箱</label>
<input type="text" name="email"/>
<input type="submit"/>
</form>
</body>
</html>
"""
@route("/")
def index2():
return htmlstr
@route("/post_to",method="POST")#post方式接受
def postto():
name=request.forms.get('name')#post方式提取参数
telephone=request.forms.get('telephone')
email=request.forms.get('email')
return (name,telephone,email)
run(debug=True,reloader=True)
2.5 Devolver diferentes tipos de datos para clientes web
from bottle import route,run,Response
@route("/")
def index():
#return {"a":"djn","b":45,"c":2.3}#1.返回字典
#return ()#2.返回空
# dec="abcd"
# return dec.encode("utf-8") #3.返回字节串
#return ("sdf","sdf")4.#返回元组或列表,不能返回嵌套的
#5.Response.charset或者Response.content_type指定返回字节编码
#Response.charset="gbk"
#Response.content_type="text/html;charset=gbk"
return "你好"
run(port="80",debug=True,reloader=True)
2.6 Usar cookies y cookies firmadas para rastrear clientes
from bottle import route,run,response,request
#1.添加cookie, response.set_cookie("name","value")
@route("/")
def index():
response.set_cookie("zoe","27")
return "set cookie!"
#2.获取cookie,request.get_cookie("name")
@route("/get_cookie")
def getcookie():
return request.get_cookie("zoe")
#3.添加签名的cookie,response.set_cookie("name","value",secret="")
@route("/setsign")
def setsign():
response.set_cookie("dz","28",secret="sfkjskfjdkfkls")
return "signed cookie"
#4.获取cookie,request.get_cookie("name",secret="")
@route("/getsign")
def getsign():
return request.get_cookie("dz",secret="sfkjskfjdkfkls")
#5.普通cookie中有中文时,使用urllib.parse.quote编码,urllib.parse.unquote解码;signed_cookie不用设置
from urllib.parse import quote,unquote
@route("/chain_set")
def ch_set():
response.set_cookie("myname",quote("我是"))
return "中文cookie"
@route("/chain_get")
def ch_get():
return unquote(request.get_cookie("myname"))
run(port="80",debug=True,reloader=True)
2.7 Carga y recepción de archivos HTTP
#1.实现上传文件页面<form action ="" method="POST" enctype="multipart/form-data">,<input type="file" name="fileupload"/>,<input type="submit" value="上传文件"/>
from bottle import route,run ,request
htmlstr="""
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>BOTTLE</title>
</head>
<body>
<form action ="/get_file" method="POST" enctype="multipart/form-data">
<input type="file" name="fileupload"/>
<input type="submit" value="上传文件"/>
</form>
</body>
</html>
"""
@route("/")
def index():
return htmlstr
#2.实现接受上传文件业务的函数,request.files.get("name")
@route("/get_file",method=["GET","POST"])
def getfile():
if request.method=="GET":
return htmlstr
else:
uf=request.files.get("fileupload")
uf.save(uf.filename)
return "接受到了文件,并保存到了本地根目录"
run(port="80",debug=True,reloader=True)
2.8 Motor de plantillas incorporado
#1.嵌入python变量from bottle import template;template("{
{name}});template("Str with{
{a}} many{
{b}} values",**adict)
from bottle import route,run,template
html="""
begin:{
{name}}, {
{age}}, {
{weight}}, {
{courses}}, {
{mytest.disp()}},{
{!html_str}}:end!
% if MyScores:
<table>
<tr>
<td>subject</td>
<td>score</td>
</tr>
% for (sub,score) in MyScores.items():
<tr>
<td>{
{sub}}</td>
<td>{
{score}}</td>
</tr>
% end
</table>
% else:
没有查询到scores
% end
"""
class MyTestClass():
def __init__(self,x=0,y=0):
self.x=x
self.y=y
def disp(self):
return (self.x,self.y)
@route("/stu/<name>")
def index(name="Stranger"):
age=12
weight=23.32
html_str="<a href='sfdnsdjfn'>链接</a>"#如何把这个字符串变量传到html时,让它转义为html呢,只需要再html的变量名前加上!
courses=["english","kero"]
mytest=MyTestClass()
#参数太多时,可以打包成字典,然后再解包
# my=dict(name=name,age=age,weight=weight,courses=courses,mytest=mytest,html_str=html_str)
# return template(html,**my)
#2嵌入python代码;%开头嵌入单行代码;<%--------%>嵌入多行python代码,
MyScores={
"chinese":334,"english":23,"math":2384}
return template(html,name=name,age=age,weight=weight,courses=courses,mytest=mytest,html_str=html_str,MyScores=MyScores)
run(port="80",debug=True,reloader=True)
% include("nav.tpl"), introduce nav.tpl en la plantilla actual
% rebase("base.tpl) incrusta el archivo de plantilla actual en {
{!base}} de la plantilla principal, que en realidad está importando la plantilla principal .
##父模板base.tpl,这里引入了nav.tpl文件,然后base部分由子模版去继承添加
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
% include("nav.tpl")
{
{
!base}}
</body>
</html>
## nav.tpl文件
<div>
<a href="#">index1</a>
<a href="#">index2</a>
<a href="#">index3</a>
<a href="#">index4</a>
</div>
##html2template.tpl文件,这里继承了父模板
% rebase("base.tpl")
begin:{
{
name}}, {
{
age}}, {
{
weight}}, {
{
courses}}, {
{
mytest.disp()}},{
{
!html_str}}:end!
% if MyScores:
<table>
<tr>
<td>subject</td>
<td>score</td>
</tr>
% for (sub,score) in MyScores.items():
<tr>
<td>{
{
sub}}</td>
<td>{
{
score}}</td>
</tr>
% end
</table>
% else:
没有查询到scores
% end
Funciones de gestión de variables en la plantilla: define(nombre), get(nombre, predeterminado=Ninguno), setdefault=(nombre=valor)
Cuando la función de devolución no pasa parámetros, la variable debe tener un valor predeterminado
%setdefault("variable","dnfjk")
{
{
variable}}
Obtenga el parámetro pasado por la variable variable, si no hay una cadena, tome la no cadena como el valor predeterminado.
{
{
get("variable","no")}}
2.9 Implementación del programa del sitio web de Bottle
Use el marco síncrono de camarera o el marco asíncrono de tornado, use nginx para el proxy inverso.
El directorio de archivos es el siguiente:
El directorio de archivos es el siguiente:
-nginx
-static
----img
----css
----js
-template
manage.py
Modifique el contenido del archivo conf\nginx.conf de nginx:
#111111111111111111111111.指明nginx所代理的后端内容,就是本机上的8088端口启动的文件
upstream myserver{
ip_hash;
server localhost:8088;
server localhost:8081;
server localhost:8082;
}
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
#222222222222222222.在server函数中,写明自己的代理地址,就是1里面设置的名称myserver
location / {
root html;
index index.html index.htm;
proxy_pass http://myserver;
}
#3333333333333333333333.将静态文件映射到指定的位置
location ~ \.(jpg|jpeg|png|gif)$ {
root C:/Users/dz/Desktop/bottle/static/img;
}
location ~ \.js$ {
root C:/Users/dz/Desktop/bottle/static/js;
}
location ~ \.css$ {
root C:/Users/dz/Desktop/bottle/static/css;
}
Probar la configuración de nginx modificada con éxito
nginx -t
nginx: el archivo de configuración C:\Users\dz\Desktop\bottle\nginx-1.8.0/conf/nginx.conf la sintaxis es correcta
nginx: archivo de configuración C:\Users\dz\Desktop\bottle\nginx-1.8.0 /conf/nginx.conf prueba exitosa
iniciar nginx
nginx
#1.使用waitress同步框架部署后端:pip install waitress;tornado 是异步框架;nginx后端反向代理
from bottle import route,run,template
import sys
@route("/")
def index():
return template("templates/index.html")
port="8088"
if len(sys.argv)==2:
port=sys.argv[1]
# run(server="waitress",port=port,debug=True,reloader=True)
run(server="tornado",port=port,debug=True,reloader=True)