Notes d'étude de bouteille
- 1. Environnement
- 2. Points de connaissance
-
- 2.1 Cadre
- 2.2 Décorateur d'URL
- 2.3 404 et redirection d'url
- 2.4 Obtenir les paramètres de requête get et post
- 2.5 Renvoyer différents types de données pour les clients Web
- 2.6 Utiliser des cookies et des cookies signés pour tracer les clients
- 2.7HTTP télécharger et recevoir des fichiers
- 2.8 Moteur de modèle intégré
- 2.9 Déploiement du programme de site Web Bottle
- 2.10 Enregistrement et connexion de l'utilisateur
Les notes sont placées dans l'entrepôt : https://github.com/Turing-dz/bottle_study_notes
1. Environnement
Ouvrir cmd en tant qu'administrateur
conda create -n bottle python
conda activate bottle
pip install bottle
2. Points de connaissance
2.1 Cadre
1. Le programme serveur avec le moins de code
from bottle import run,route
@route('/')
def index():
return "I am bottle"
run(host="localhost",port="80",debug=True,deloader=True)
2. Utiliser un framework de programme serveur orienté objet
from bottle import Bottle,run
web=Bottle()
@web.route("/")
def index():
return "I am bottle2"
run(web)
Le serveur exécute la fonction run, en spécifiant l'adresse IP et le port d'exécution du serveur (hôte, port); en affichant les informations de débogage (debug); en redémarrant automatiquement le service après la modification du code (deloader)
2.2 Décorateur d'URL
1. La réponse par défaut à la requête get, vous pouvez définir la méthode pour répondre à une variété de méthodes de requête, request.method pour déterminer la méthode de requête
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. Routage dynamique
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 et redirection d'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 Obtenir les paramètres de requête get et post
1. Obtenir la fourniture du paramètre : url link add "? name = value & name = value..."
obtenir l'acquisition du paramètre : request.query.name (lorsque le nom n'existe pas, renvoie une chaîne vide)
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. Fourniture du paramètre post : ajoutez method="post" au formulaire soumis.
Obtenez le paramètre post : 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 Renvoyer différents types de données pour les clients 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 Utiliser des cookies et des cookies signés pour tracer les clients
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.7HTTP télécharger et recevoir des fichiers
#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 Moteur de modèle intégré
#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"), introduire nav.tpl dans le modèle actuel
% rebase("base.tpl) incorporer le fichier de modèle actuel dans {
{!base}} du modèle parent, qui importe en fait le modèle parent .
##父模板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
Fonctions de gestion des variables dans le template : define(name), get(name, default=None), setdefault=(name=value)
Lorsque la fonction de retour ne passe pas de paramètres, la variable doit avoir une valeur par défaut
%setdefault("variable","dnfjk")
{
{
variable}}
Obtenez le paramètre passé par la variable variable, s'il n'y a pas de chaîne, prenez la chaîne no comme valeur par défaut.
{
{
get("variable","no")}}
2.9 Déploiement du programme de site Web Bottle
Utilisez le framework synchrone de serveuse ou le framework asynchrone de tornade, utilisez nginx pour le proxy inverse.
Le répertoire du fichier est le suivant :
Le répertoire du fichier est le suivant
-nginx
-static
----img
----css
----js
-template
manage.py
Modifiez le contenu du fichier 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;
}
La configuration du test nginx a été modifiée avec succès
nginx -t
nginx : la syntaxe du fichier de configuration C:\Users\dz\Desktop\bottle\nginx-1.8.0/conf/nginx.conf est correcte
nginx : le fichier de configuration C:\Users\dz\Desktop\bottle\nginx-1.8.0 Le test /conf/nginx.conf est réussi
démarrer 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)