Python Flask学习
一:Flask应用
必须在项目导入flask模块,flask类的一个对象是我们的WSGI应用程序
Flask构造函数使用当前模块(__name__)的名称作为参数
Flask类的route()函数是一个装饰器,他告诉应用程序那个URL因该调用相关的函数
from flask import Flask app = Flask(__name__) #相当于app.add_url_rule('/','/','hello_world')
@app.route('/') def hello_word(): return "Hello World" if __name__ == "__main__": app.run()
#访问页面输出Hello World
- @app.route(rule,options)
- rule参数表示与该函数的URL绑定
- options是要转发给基础RULE对象的参数列表
- 在上面的示例中,'/'URL与hello_world()函数绑定,因此,当在浏览器中打开web服务器的主页时,将呈现该函数的输出
- app.run(host,port,debug,options)
- host:监听的主机名,设置为0.0.0.0都可以访问
- port:监听端口值
- debug:调试,如果更改代码服务器会自动重启,提供一个有用的调试器来跟踪应用程序的错误
- options:要转发到底层的Werkzebug服务器
二:Flask路由
- @app.route('/user/<username>')
- @app.route('/post/<int:post_id>')
- @app.route('/post/<float:post_id>')
- @app.route('/post/<path:path>')
- @app.route('/login', methods=['GET', 'POST'])
现代Web框架使用路由技术来帮助用户记住应用程序的URL,可以直接访问所需的页面,而无需从主页导航,Flask中的route()装饰器用于将URL绑定到函数
from flask import Flask app = Flask(__name__) #下面的语句相当于app.add_url_rule('/','hello','hello_word')用于将函数和url绑定 @app.route('/hello') def hello_word(): return "Hello World"
@app.route('/hello')在这里,URL:'/hello'规则绑定到hello_world函数,因此用户访问http://127.0.0.1:5000/hello页面将显示hello world
参数:
@app.route和app.add_url_rule参数: rule, URL规则 view_func, 视图函数名称 defaults=None, 默认值,当URL中无参数,函数需要参数时,使用defaults={'k':'v'}为函数提供参数 endpoint=None, 名称,用于反向生成URL,即: url_for('名称') methods=None, 允许的请求方式,如:["GET","POST"] strict_slashes=None, 对URL最后的 / 符号是否严格要求, 如: @app.route('/index',strict_slashes=False), 访问 http://www.xx.com/index/ 或 http://www.xx.com/index均可 @app.route('/index',strict_slashes=True) 仅访问 http://www.xx.com/index redirect_to=None, 重定向到指定地址 如: @app.route('/index/<int:nid>', redirect_to='/home/<nid>') 或 def func(adapter, nid): return "/home/888" @app.route('/index/<int:nid>', redirect_to=func) subdomain=None, 子域名访问 from flask import Flask, views, url_for app = Flask(import_name=__name__) app.config['SERVER_NAME'] = 'wupeiqi.com:5000' @app.route("/", subdomain="admin") def static_index(): """Flask supports static subdomains This is available at static.your-domain.tld""" return "static.your-domain.tld" @app.route("/dynamic", subdomain="<username>") def username_index(username): """Dynamic subdomains are also supported Try going to user1.your-domain.tld/dynamic""" return username + ".your-domain.tld" if __name__ == '__main__': app.run()
三:Flask变量规则
通过向规则参数添加变量部分,可以动态构建URL,此变量部分标记为<variable-name>,他作为关键参数传递给与规则相关联的函数
在一下示例中,route()装饰器的规则参数包含附加到URL '/hello'的<name>。如果在浏览器中访问http://127.0.0.1:5000/hello/github,则'github'将作为参数提供给hello()函数
from flask import Flask app = Flask(__name__) #访问http://127.0.0.1:5000/hello/github页面返回hello welcome to github @app.route('/hello/<name>') def hello(name): return "hellow welcome to %s"%name if __name__ == "__main__": app.run()
除了默认字符串变量部分之外,还可以提供以下转换器构建规则
- int:接受整数
- float:对于浮点值
- path:接受用作目录分隔符的斜杠
@app.route('/blog/<int:ID>') def show_blog(ID): return "blog number %d"%id @app.route('/blog/<float:FID>') def get_fid(FID): return "blog floatnumber %f"%FID
访问http://127.0.0.1:5000/blog/11返回blog number 11
注意上述的<int:ID>与show_blog(ID)中的参数名要一样
四:Flask的URL唯一性
@app.route('/python')
def hellopy(): return "hello python" @app.route('/flask/') def hellofl(): return "hellow Flask"
访问第一个规则页面http://127.0.01:5000/python正常,但访问/python/爆404
访问第二规则页面会自动在后面加上/(后面开始没有/时),这是一个规范的url
五:Flask Url构建
url_for函数对于动态构建特定函数的URL非常有用,该函数接收函数的名称作为第一个参数,以及一个或多个关键字参数,每个参数对应URL的变量部分
redirect模块用于url跳转,url_for(url,options)指定跳转的页面和参数
from flask import redirect, url_for
@app.route('/admin') def hello_admin(): return "hello admin" @app.route('/guest/<guest>') def hello_guest(guest): return "Hello %s as Guest" % guest @app.route('/user/') def hello_user(name): if name == 'admin': return redirect(url_for('hello_admin')) else: return redirect(url_for('hello_guest', guest=name))
打开浏览器并输入URL http://localhost:5000/user/admin
浏览器中的应用程序响应是: Hello Admin
ur:http://127.0.0.1:5000/admin
在浏览器中输入以下URL http://localhost:5000/user/ppp
应用程序响应现在更改为:Hello ppp as Guest
url:http://127.0.0.1:5000/guest/guest
上述脚本有一个函数 hello_user(name),它接受来自 URL 的参数的值。
hello_user() 函数检查接收的参数是否与 ‘admin’ 匹配。如果匹配,则使用 url_for() 将应用程序重定向到 hello_admin() 函数,否则重定向到将接收的参数作为 guest 参数传递给它的 hello_guest() 函数。
六:Flask HTTP方法
GET请求获取表单数据值用request.args.get('key')
POST请求获取表单数据值用 request.form['key']
from flask import redirect, url_for, request‘ @app.route('/login', methods=['POST', 'GET']) def login(): print(request.method)
#判断请求方法 if request.method == "POST":
获取以post方式提交的数据 user = request.form['nm']
跳转到success函数 return redirect(url_for('success', name=user)) else:
#获取get提交的参数 user = request.args.get('nm') return redirect(url_for('success', name=user))
login.html
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <form action="http://127.0.0.1:5000/login" method="post"> <p>Enter Name:</p> <input type="text" name="nm" /> <input type="submit" value="submit" /> </form> </body> </html>
七:Flask模板
术语‘web templating system(web模板系统)’指的是设计一个HTML脚本,其中可以动态插入变量数据。web模板系统包括模板引擎,某种数据源和模板处理器。
Flask使用jinga2模板引擎。Web模板包含用于变量和表达式(在这些情况下为Python表达式)的HTML语法散布占位符,这些是在呈现模板时替换的值
return render_template('hello.html',name=user)返回一个hello.html的模板,模板中name变量user的值
<!DOCTYPE html> <html> <head> <title>get请求示例</title> </head> <body> {{name}} <form action="/deal_request" method="get"> <input type="text" name="q" /> <input type="submit" value="搜索" /> </form> </body> </html>
@app.route('/hello/<user>') def index(user): #返回template下的某个html文件 return render_template('get.html',name=user)
访问http://127.0.0.1:5000/hello/aaa 页面显示aaa
- jinja2模板引擎使用以下分隔符从HTML转义
- {% %} 用于语句
- {{ }} 用于表达式可以打印到模板输出
- {# #} 用于未包含在模板输出中的注释
- # ## 用于语句
- 在模板中使用条件语句
{% if name %} <h1>Hello {{name}}</h1> {% else %} <h1>Hello hello.html</h1> {% endif %}
@app.route('/hello/<user>') def index(user): #返回template下的某个html文件,这里的name与hello.html中name需一致 return render_template('hello.html',name=user)
八:Flask静态文件
Web应用程序通常需要静态文件,例如javascript文件或支持网页显示的CSS文件。通常,配置Web服务器并为您提供这些服务,但在开发过程中,这些文件是从您的包或模块旁边的static文件夹中提供,它将在应用程序的/static中提供。
特殊端点'static'用于生成静态文件的URL。
在下面的示例中,在index.html中的HTML按钮的OnClick事件上调用hello.js中定义的javascript函数,该函数在Flask应用程序的“/”URL上呈现。
@app.route("/") def index(): return render_template("index.html") if __name__ == '__main__': app.run(debug = True)
<html> <head> <script type = "text/javascript" #相当于src={{url_for(/static/hello.js)}} src = "{{ url_for('static', filename = 'hello.js') }}" ></script> </head> <body> <input type = "button" onclick = "sayHello()" value = "Say Hello" /> </body> </html>
function sayHello() { alert("Hello World") }
九:Flask Request对象
来自客户端网页的数据作为全局请求对象发送到服务器。为了处理请求数据,应该从Flask模块导入。
Request对象的重要属性如下所列:
-
Form - 它是一个字典对象,包含表单参数及其值的键和值对。
-
args - 解析查询字符串的内容,它是问号(?)之后的URL的一部分。
-
Cookies - 保存Cookie名称和值的字典对象。
-
files - 与上传文件有关的数据。
-
method - 当前请求方法。
十:Flask 将表单数据发送到模板
我们已经看到,可以在URL规则中指定http方法。触发函数接收的Form数据可以以字典对象的形式收集它并将其转发到模板以在相应的网页上呈现它。
在以下示例中,'/' URL会呈现具有表单的网页(student.html)。填入的数据会发布到触发 result()函数的'/result' URL。
results()函数收集字典对象中的request.form中存在的表单数据,并将其发送给result.html。
该模板动态呈现表单数据的HTML表格。
获取POST提交的数据request.form,reques.form['key'],
获取GET提交的数据request.args.get()
from flask import Flask, render_template, request app = Flask(name) @app.route('/') def student(): return render_template('student.html') @app.route('/result',methods = ['POST', 'GET']) def result(): if request.method == 'POST': result = request.form return render_template("result.html",result = result) if name == 'main': app.run(debug = True)
<form action = "http://localhost:5000/result" method = "POST"> <p>Name <input type = "text" name = "Name" /></p> <p>Physics <input type = "text" name = "Physics" /></p> <p>Chemistry <input type = "text" name = "chemistry" /></p> <p>Maths <input type ="text" name = "Mathematics" /></p> <p><input type = "submit" value = "submit" /></p> </form>
<table border = 1> {% for key, value in result.items() %} <tr> <th> {{ key }} </th> <td> {{ value }} </td> </tr> {% endfor %} </table>
十一:Flask Cookie
在Flask中操作cookie,是通过response对象来操作,可以在response返回之前,通过response.set_cookie来设置,这个方法有以下几个参数需要注意:
key:设置的cookie的key。
value:key对应的value。
max_age:改cookie的过期时间,如果不设置,则浏览器关闭后就会自动过期。
expires:过期时间,应该是一个datetime类型。
domain:该cookie在哪个域名中有效。一般设置子域名,比如cms.example.com。
path:该cookie在哪个路径下有效。
获取:request.cookies.get(key)
设置:resp.set_cookie(key, value, max_age=整数)
删除:resp.delete_cookie(key)
from flask import Flask, request, Response, render_template app = Flask(__name__) @app.route('/') def index(): return render_template('index.html') @app.route('/setcookie') def setcookie(): name = request.args.get('username') #设置cookie resp = Response() resp.set_cookie('username',name) return resp @app.route('/getcookie') def getcookie(): cookie=request.cookies.get('username') return render_template('getcookie.html',cookie=cookie) if __name__ == '__main__': app.run(port=3000)
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
{{cookie}}
</body>
</html>
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <form action="/setcookie"> <input type="text" name="username" /> <input type="submit" name="提交" /> </form> </body> </html>>
十二:Flask Sessions
Flask中的session是通过from flask import session。然后添加值key和value进去即可。
client side session:Flask中的session机制是将session信息加密,然后存储在cookie中。专业术语叫做client side session。
server side session:存储在服务器,客户端保存的时session_id(通过cookie完成)
使用:
获取:session.get(key, '默认值')
session.permanent = True
session[key] = value
session.pop('key')
session.clear()
from flask import Flask, session, redirect, url_for, escape, request app = Flask(__name__) @app.route('/') def index(): if 'username' in session: return 'Logged in as %s' % escape(session['username']) return 'You are not logged in' @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': #设置session的值 session['username'] = request.form['username'] #重定向url return redirect(url_for('index')) return ''' <form action="" method="post"> <p><input type=text name=username> <p><input type=submit value=Login> </form> ''' @app.route('/logout') def logout(): # remove the username from the session if it's there #删除session中的某个值 session.pop('username', None) return redirect(url_for('index')) # set the secret key. keep this really secret: #session密钥 app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
十三:Flask重定向和错误
@app.route('/') def index(): return render_template('login.html') @app.route('/login', methods=['POST', 'GET']) def login(): if request.method == "POST" and request.form['username'] == 'admin': #重定向success页面 return redirect(url_for('success')) #重定向index页面 return redirect(url_for('index')) @app.route('/success') def success(): return "login in successful"
在上述函数中:
-
location参数是应该重定向响应的URL。
-
statuscode发送到浏览器标头,默认为302。
-
response参数用于实例化响应。
以下状态代码已标准化:
- HTTP_300_MULTIPLE_CHOICES
- HTTP_301_MOVED_PERMANENTLY
- HTTP_302_FOUND
- HTTP_303_SEE_OTHER
- HTTP_304_NOT_MODIFIED
- HTTP_305_USE_PROXY
- HTTP_306_RESERVED
- HTTP_307_TEMPORARY_REDIRECT
@app.route('/') def index(): return render_template('login.html') @app.route('/login',methods=['POST','GET']) def login(): if request.method=='POST': if request.form['username']=='admin': return redirect(url_for('success')) else: #错误请求返回状态码 abort(401) return redirect(url_for('index')) @app.route('/success') def success(): return "login in successfully"
Flask.abort(code)
Code参数采用以下值之一:
-
400 - 用于错误请求
-
401 - 用于未身份验证的
-
403 - Forbidden
-
404 - 未不到
-
406 - 表示不接受
-
415 - 用于不支持的媒体类型
-
429 - 请求过多
十三:Flask消息闪现
一个好的基于GUI的应用程序会向用户提供有关交互的反馈。例如,桌面应用程序使用对话框或消息框,JavaScript使用警报用于类似目的。
在Flask Web应用程序中生成这样的信息性消息很容易,那就是flash,只显示一次数据就没有了
flash(v)存储值
get_flashed_messages()获取值
@app.route('/') def index(): #获取消息内容 print(get_flashed_messages()) return render_template('login.html') @app.route('/set') def index2(): v=request.args.get('p') #存储值 flash(v) return 'ok' if __name__ == '__main__': app.secret_key='ddwadaw' app.run(port=9000)flask
{% with messages = get_flashed_messages() %} {% if messages %} {% for message in messages %} {{message}} {% endfor %} {% endif %} {% endwith %}
十四:文件上传
在Flask中处理文件上传非常简单。它需要一个HTML表单,其enctype属性设置为“multipart / form-data”,将文件发布到URL。URL处理程序从request.files[]对象中提取文件,并将其保存到所需的位置。每个上传的文件首先会保存在服务器上的临时位置,然后将其实际保存到它的最终位置
但是,建议使用secure_filename()函数获取它的安全版本。
f = request.files['file']获取文件对象
f.save(secure_filename(f.filename))保存文件
<!DOCTYPE html> <html> <head> <title></title> </head> <body> <form action="/uploader" method="post" enctype="multipart/form-data"> <input type="file" name="file" /> <input type="submit" /> </form> </body> </html>>
@app.route('/upload') def upload(): return render_template('upload.html') @app.route('/uploader', methods=['GET', 'POST']) def upload_file(): if request.method == 'POST': #获取文件对象 f = request.files['file'] print(f) #保存文件 f.save(secure_filename(f.filename)) return 'file uploaded successfully'
十五:Flask WTF
validators验证器
1 .DataRequired(检查输入字段是否为空)
2.Email(检查字段中的文本是否遵循电子邮件ID约定)
3.IPAddress(在输入字段中验证IP地址)
4.Length(验证输入字段中的字符串的长度是否在给定范围内)
5.NumberRange(验证给定范围内输入字段中的数字)
6.URL(验证在输入字段中输入的URL)
标准表单字段
序号 | 标准表单字段与描述 |
---|---|
1 |
TextField 表示<input type ='text'> HTML表单元素 |
2 |
BooleanField 表示<input type ='checkbox'> HTML表单元素 |
3 |
DecimalField 用于显示带小数的数字的文本字段 |
4 |
IntegerField 用于显示整数的文本字段 |
5 |
RadioField 表示<input type = 'radio'> HTML表单元素 |
6 |
SelectField 表示选择表单元素 |
7 |
TextAreaField 表示<testarea> HTML表单元素 |
8 |
PasswordField 表示<input type = 'password'> HTML表单元素 |
9 |
SubmitField 表示<input type = 'submit'>表单元素 |
#!/usr/bin/env python # -*- coding:utf-8 -*- from flask import Flask, render_template, request, redirect from wtforms import Form from wtforms.fields import core from wtforms.fields import html5 from wtforms.fields import simple from wtforms import validators from wtforms import widgets app = Flask(__name__) app.debug = True class LoginForm(Form): name = simple.StringField( #标签, label='用户名', #验证器的验证条件 validators=[ validators.DataRequired(message='用户名不能为空.'), validators.Length( min=6, max=18, message='用户名长度必须大于%(min)d且小于%(max)d') ], #html标签表单类型 widget=widgets.TextInput(), #标签属性 render_kw={'class': 'form-control'} ) pwd = simple.PasswordField( label='密码', validators=[ validators.DataRequired(message='密码不能为空.'), validators.Regexp(regex="^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,}", message='密码至少8个字符,至少1个大写字母,1个小写字母,1个数字和1个特殊字符') ], widget=widgets.PasswordInput(), render_kw={'class': 'form-control'} ) @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'GET': #创建一个LoginForm()对象,就是一个html页面 form = LoginForm() # return render_template('login.html', form=form) else: #POST型传入html页面的参数用formdata form = LoginForm(formdata=request.form) if form.validate(): print('用户提交数据通过格式验证,提交的值为:', form.data) else: print(form.errors) return render_template('login.html', form=form) if __name__ == '__main__': app.run() app.py
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>登录</h1> <form method="post"> <!--<input type="text" name="name">--> <p>{{form.name.label}} {{form.name}} {{form.name.errors[0]}}</p> <!--<input type="password" name="pwd">--> <p>{{form.pwd.label}} {{form.pwd}} {{form.pwd.errors[0]}}</p> <input type="submit" value="提交"> </form> </body> </html> login.html
用户注册
from flask import Flask, request, render_template from wtforms import Form from wtforms.fields import simple from wtforms import validators from wtforms import widgets from wtforms.fields import html5 from wtforms.fields import core class RegistForm(Form): uname = simple.TextField( label='用户名', validators=[ validators.DataRequired(message='用户名不能为空')], widget=widgets.TextInput(), render_kw={'class': 'form-control'}) passwd = simple.PasswordField( label='密码', validators=[ validators.DataRequired(message='密码不能为空'), validators.Length(min=6, max=8, message='密码长度不符合规则') ], widget=widgets.PasswordInput(), render_kw={'clas': 'form-control'}) confirm_pwd = simple.PasswordField( label='确认密码', validators=[ validators.DataRequired(message='确认密码不能为空'), validators.EqualTo(fieldname='passwd', message='密码不一致'), ], widget=widgets.PasswordInput(), render_kw={'class': 'form-control'}) email = html5.EmailField( label='邮箱地址', validators=[ validators.DataRequired(message='邮箱不可为空'), validators.Email(message='邮箱地址格式错误'), ], widget=widgets.TextInput(), render_kw={'class': 'form-control'}) gender = core.RadioField( label='性别', choices=( (1, '男'), (2, '女')), coerce=int,) city = core.SelectField( label='城市', choices=( (1, '广州'), (2, '北京'),)) favor = core.SelectMultipleField( label='喜好', choices=( (1, '篮球'), (2, '足球'), ), widget=widgets.ListWidget(prefix_label=False), option_widget=widgets.CheckboxInput(), coerce=int, default=[1, 2] ) # 可以实现动态获取数据,并显示到前端 def __init__(self,*args,**kwargs): super(RegistForm, self).__init__(*args,**kwargs) self.favor.choices = ((1, '篮球'), (2, '足球'), (3, '羽毛球')) app = Flask(__name__) @app.route('/regist', methods=['GET', 'POST']) def regist(): if request.method == 'GET': form = RegistForm() return render_template('regist.html', form=form) else: form = RegistForm(formdata=request.form) if form.validate(): print("数据校验成功") else: print("数据校验失败") return render_template('regist.html', form=form) if __name__ == '__main__': app.run(port=4444)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>用户注册</h1> <form method="post" novalidate style="padding:0 50px"> {% for item in form %} <p>{{item.label}}: {{item}} {{item.errors[0] }}</p> {% endfor %} <input type="submit" value="提交"> </form> </body> </html>
十六:Flask SqlAlchemy
创建数据库链接
engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/student", encoding='utf-8')
engine=create_engine(
"mysql+pymysql://root:root@127.0.0.1:3306/student",
max_overflow=0,#超过链接池大小外最多创建的链接
pool_size=5,#连接池大小
pool_timeout=30,#池中没有链接最多等待的时间,超过则报错
pool_recycle=1#多久之后对链接进行一次回收
from sqlalchemy import Column, Integer, String #创建数据库链接 engine = create_engine("mysql+pymysql://root:root@127.0.0.1:3306/student", encoding='utf-8') Base = declarative_base() # 生成orm基类 class User(Base): __tablename__ = 'alex' #创建数据库的表名 id = Column(Integer, primary_key=True)#创建数据库中相应的列名 name = Column(String(32)) password = Column(String(64)) Base.metadata.create_all(engine) # 创建表结构
1)创建连接池,数据库写入数据
engine=create_engine('mysql+pymysql://root:root@127.0.0.1:3306/student',max_overflow=0,pool_size=5)
Session=sessionmaker(bind=engine
从连接池中获取数据库链接
session=Session()
from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine import Flask #创建连接池 engine=create_engine('mysql+pymysql://root:root@127.0.0.1:3306/student',max_overflow=0,pool_size=5) Session=sessionmaker(bind=engine) #从连接池中获取数据库链接 session=Session() #执行ORM操作,添加数据 obj1=Flask.Users(id=3,name='LLL',age=16,email='44@qq.com',extra='whoami') session.add(obj1) session.commit() #关闭数据库链接(其实是将数据库链接放回连接池) session.close()
Session=sessionmaker(bind=engine)
from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session from sqlalchemy.orm import sessionmaker import Flask #创建连接池 engine=create_engine('mysql+pymysql://root:root@127.0.0.1:3306/student') Session=sessionmaker(bind=engine) #从连接池中获取数据库链接 #scope_session()会自动为每个获取链接的线程创建一个session session=scoped_session(Session) #执行ORM操作 obj1=Flask.Users(id=4,name='pp',age=18,email='55@qq.com') session.add(obj1) session.commit()
session和scope_session的区别
当执行了 commit 操作的后, 数据才会写入数据库. 此时数据库里面已经有了 数据. 即不同的session 是关联不同的表, 一个session 如果有关联一个 从base 继承的对象, 其他的session 是不能够关联这个对象的. 就相当于把 session 和 对象绑定在一起了.此时 数据库里面 就有两条数据了. session不进行 close,或者回滚, 其他的session 是不能添加 p 这个对象的. 测试发现 同一对象, 只能提交到数据库一次.
0x01数据库增操作
单行增加(session.add(obj1))
from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session from sqlalchemy.orm import sessionmaker import Flask #创建连接池 engine=create_engine('mysql+pymysql://root:root@127.0.0.1:3306/student') Session=sessionmaker(bind=engine) #从连接池中获取数据库链接 #scope_session()会自动为每个获取链接的线程创建一个session session=scoped_session(Session) #执行ORM操作 obj1=Flask.Users(id=4,name='pp',age=18,email='55@qq.com') session.add(obj1) session.commit()
批量增加(session.add_all([obj1,obj2]))
from sqlalchemy.orm import sessionmaker from sqlalchemy import create_engine import Flask #创建连接池 engine=create_engine('mysql+pymysql://root:root@127.0.0.1:3306/student',max_overflow=0,pool_size=5) Session=sessionmaker(bind=engine) #从连接池中获取数据库链接 session=Session() #执行ORM操作,添加数据 obj2=Flask.Users(id=6,name='www',age=11,email='Rr@qq.com') obj1=Flask.Users(id=7,name='ppp',age=11,email='ui@qq.com',extra='whoami') session.add_all([obj1,obj2]) session.commit() #关闭数据库链接(其实是将数据库链接放回连接池) session.close()
0x02数据库查询
-
查询所有Users表中的内容
r1=session.query(Flask.Users).all()
- 查询Users表中的name和age字段,并为name字段起个别名为'xx'
r2=session.query(Flask.Users.name.label('xx'),Flask.Users.age).all()
- 查询Users表中name字段等于lanfei的所有字段信息
r3=session.query(Flask.Users).filter(Flask.Users.name=='lanfei').all()
- 查询Users表中name=lanfei的所有值
r4=session.query(Flask.Users).filter_by(name='lanfei').all()
r5=session.query(Flask.Users).filter_by(name='lanfei').first()
- 查询id<24,name=lanfei的所有数据
r6=session.query(Flask.Users).filter(text("id<:value and name=:name")).params(
value=24,name='lanfei').order_by(Flask.Users.id).all()
- 查询user表中name=lanfei的所有字段数据
r7=session.query(Flask.Users).from_statement(text("select * from user where name=:name")).params(name='lanfei').all()
from sqlalchemy import create_engine from sqlalchemy.orm import scoped_session from sqlalchemy.orm import sessionmaker from sqlalchemy.sql import text import Flask engine=create_engine('mysql+pymysql://root:root@127.0.0.1:3306/student',max_overflow=0,pool_size=5) Session=sessionmaker(bind=engine) session=Session() 查询所有Users表中的内容 r1=session.query(Flask.Users).all() for item in r1: print(item.name) print('\t',item.age) print('\t',item.email) 查询Users表中的name和age字段,并为name字段起个别名为'xx' r2=session.query(Flask.Users.name.label('xx'),Flask.Users.age).all() for item in r2: print(item.xx) print('\t',item.age) 查询Users表中name字段等于lanfei的所有字段信息 r3=session.query(Flask.Users).filter(Flask.Users.name=='lanfei').all() for item in r3: print(item.name+'\n\t'+item.email) print(item.age) 查询Users表中name=lanfei的所有值 r4=session.query(Flask.Users).filter_by(name='lanfei').all() r5=session.query(Flask.Users).filter_by(name='lanfei').first() print(r5.name) 查询id<24,name=lanfei的所有数据 r6=session.query(Flask.Users).filter(text("id<:value and name=:name")).params( value=24,name='lanfei').order_by(Flask.Users.id).all() for item in r6: print(item.name) 查询user表中name=lanfei的所有字段数据 r7=session.query(Flask.Users).from_statement(text("select * from user where name=:name")).params(name='lanfei').all() for item in r7: print(item.name)
0x03数据库删除(必须commit,不然不会生效)
session.query(Users).filter(Users.id > 2).delete()
session.commit()
0x04数据库修改
- 修改数据库中User表中id==1的用户名
session.query(Flask.Users).filter(Flask.Users.id==1).update({'name':'xxx'})
session.commit()
- 将数据库中Users表中id==1的用户名拼接一个字符串
session.query(Flask.Users).filter(Flask.Users.id==1).update(
{Flask.Users.name:Flask.Users.name+"099"},synchronize_session=False)
- 将数据库中id>0的age全部+1
session.query(Users).filter(Users.id > 0).update({"age": Users.age + 1}, synchronize_session="evaluate")
Sqlachemy常用操作
#查询userid>1并且username=eric的数据
ret = session.query(Users).filter(Users.id > 1, Users.name == 'eric').all()
#between()查看userid在1,3并且name=eric的数据
ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'eric')
.all()
#userid.in_查询userid是1,3,4的数据
ret = session.query(Users).filter(Users.id.in_([1,3,4])).all()
#~userid.in_查询userid不是1,3,4的数据
ret = session.query(Users).filter(~Users.id.in_([1,3,4])).all()
#嵌套使用
ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='eric'))).all()
#and_ 查询userid>3并且name=p的数据 ret=session.query(Flask.Users).filter(and_(Flask.Users.id>3),Flask.Users.name=='pp').all() #or_ 查询userid>3或者Users.name=='www'的数据 ret=session.query(Flask.Users).filter(or_(Flask.Users.id>3,Flask.Users.name=='www')).all()
#########################通配符 %通配符,匹配多个 ret=session.query(Flask.Users).filter(Flask.Users.name.like('p%')).all() ‘~’,‘%’查询不是以p开头的数据 ret=session.query(Flask.Users).filter(~Flask.Users.name.like('p%')).all() 字符切片切取查询到的数据 ret=session.query(Flask.Users)[1:2] ######################排序 查询user表中的所有数据,按username的降序排列 ret=session.query(Flask.Users).order_by(Flask.Users.name.asc()).all() 查询user表中的所有数据,按username的升序排列 ret=session.query(Flask.Users).order_by(Flask.Users.name.desc()).all() ####################分组 以userage做为分组条件进行查询 ret=session.query(Flask.Users.age).group_by(Flask.Users.age).all() 以username作为分组条件,查询函数中的数据 ret=session.query( func.max(Flask.Users.id), func.sum(Flask.Users.id), func.min(Flask.Users.id)).group_by(Flask.Users.name).all() 以having子句作为查询条件,过滤查询 ret=session.query( func.max(Flask.Users.id), func.sum(Flask.Users.id), func.min(Flask.Users.id)).group_by(Flask.Users.name).\ having(func.min(Flask.Users.id)>2).all() #########################连表 内联 ret=session.query(Flask.Person).join(Flask.Hobby).all() 左外连 ret=session.query(Flask.Person).join(Flask.Hobby,isouter=True) ######################组合 #union联合查询,union会自动将重复的数据进行合并 q1=session.query(Flask.Users.name).filter(Flask.Users.id>2) q2=session.query(Flask.Users.age).filter(Flask.Users.id<2) print(q1.union(q2)) #Union_all联合查询,不会将重复的数据进行合并,所以效率更高 q1 = session.query(Users.name).filter(Users.id > 2) q2 = session.query(Favor.caption).filter(Favor.nid < 2) ret = q1.union_all(q2).all()
Sqlachemy之一对多relationship
sqlachemy连表查询
hobby=relationship('Hobby',backref='pers')#自动连表
连表查询外键相等的数据 ''' SELECT person.nid AS person_nid, person.name AS person_name, person.hobby_id AS person_hobby_id, hobby.id AS hobby_id, hobby.caption AS hobby_caption FROM person LEFT OUTER JOIN hobby ON hobby.id = person.hobby_id ''' res=session.query(Flask.Person,Flask.Hobby).join(Flask.Hobby,isouter=True).all() print(res) for item in res: print(item.Person.name,item.Hobby.caption) # relation自动连表(正向查询),相当于自动将hobby表挂到了person表 res=session.query(Flask.Person).first() # print(res.hobby.id,res.hobby.caption,res.name) #反向查询,pers=person表,相当于将person表挂到hobby下 # res=session.query(Flask.Hobby).first() # print(res.caption,res.pers[0].name)
sqlachemy之relationship增加数据
#在person表中添加name为lucy,hobby_id=4的数据,在hobby表中添加id=4,caption为哟用的数据 session.add(Flask.Person(name='lucy',hobby=Flask.Hobby(id=4,caption='游泳'))) #在hobby表中添加caption为赛车的数据,在person表中添加name=alin,name= bubp,hobby_id为赛车的id的数据 hb=Flask.Hobby(caption='赛车') #person表里的hobby_id为赛车 hb.pers=[Flask.Person(name='alin'),Flask.Person(name='bubp')] session.add(hb)
Sqlachemy之多对多relationship
1)sqlachemy之多对多添加数据
#反向添加男女对应关系 g1=Flask.Girl(hostname='shali') g1.boys=[Flask.Boy(name='jorge'),Flask.Boy(name='toke')] session.add(g1) session.commit() #正向查询 kenn=session.query(Flask.Boy)[2] print(kenn.name,kenn.servers[2].hostname)
2)sqlachemy之多对多查询
#正向查询 # kenn=session.query(Flask.Boy)[2] # print(kenn.name,kenn.servers[2].hostname) #反向查询 kenn=session.query(Flask.Girl)[4] print(kenn.hostname,kenn.boys[0].name,kenn.boys[1].name)
关联子查询
subqry = session.query(func.count(Server.id).label("sid")).filter(Server.id == Group.id).correlate(Group).as_scalar() result = session.query(Group.name, subqry) """ SELECT `group`.name AS group_name, (SELECT count(server.id) AS sid FROM server WHERE server.id = `group`.id) AS anon_1 FROM `group`
十七 Flask配置文件
导入配置
app.config.from_object('sansa.settings.Developmentconfig')
flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为: { 'DEBUG': get_debug_flag(default=False), 是否开启Debug模式 'TESTING': False, 是否开启测试模式 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': timedelta(days=31), 'USE_X_SENDFILE': False, 'LOGGER_NAME': None, 'LOGGER_HANDLER_POLICY': 'always', 'SERVER_NAME': None, 'APPLICATION_ROOT': None, 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': timedelta(hours=12), 'TRAP_BAD_REQUEST_ERRORS': False, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': True, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, }
十八Flask之蓝图
1、蓝图的作用
蓝图用于为应用提供目录划分
2、蓝图注册
app.register_blueprint(account)
3、生成蓝图对象
account=Blueprint('account',__name__,url_prefix='/admin',template_folder='pls')
Flask扩展
1、before_request(请求网页前做的操作)
@account.before_request
def process(*args,**kwargs):
print('来了')
2、afer_request(请求网页后做的操作)
@app.template_global
def xx():
print('请求之后')
3、template_global(html模板定制)
@app.template_global()
def sb(a1, a2):
return a1 + a2
调用方式:{{sb(1,2)}}
4、template_filter(html模板定制)
@app.template_filter()
def db(a1, a2, a3):
return a1 + a2 + a3
调用方式:{{ 1|db(2,3)}}