1.Flask配置文件之from_object篇
app = Flask(__name__)
app.config.from_object(Flask.config[config_name])
Flask.config[config_name].init_app(app)
#app是通过Flask创建的,app的config方法肯定是从Flask类里面获得的
查看原码可以发现app的config属性的定义
self.config=self.make_config(instance_relative_config)
make_config(instance_relative_config)这个函数定义的内容
def make_config(self,instance_relative=False):
return self.config_class(root_path,self.default_config)
#最终返回的是一个config_class方法,它是一个类对象,这个类对象是从Config类而来。
#这种方式的效果是直接从文件中加载对项目的配置
2.flask第三方扩展之Moment模块
Moment.js 是一个简单易用的轻量级JavaScript日期处理类库,提供了日期格式化、日期解析等功能。
它支持在浏览器和NodeJS两种环境中运行。此类库能够 将给定的任意日期转换成多种不同的格式,具有
强大的日期计算功能,同时也内置了能显示多样的日期形式的函数。另外,它也支持多种语言,你可以
任意新增一种 新的语言包。
#首先初始化Flask-Moment
from flask.ext.moment import Moment
moment = Moment(app)
在base.html模板种的head标签中导入moment.js,jquery.js
<html>
<head>
{{ moment.include_jquery() }}
{{ moment.include_moment() }}
<!--使用中文,默认是英语的-->
{{ moment.lang("zh-CN") }}
</head> <body> ... </body> </html>
使用Flask-moment
from flask import render_template
from datetime import date
@main.route('/')
def index ():
return render_template('index.html', time = date(1994,8,29))
#在模板中渲染
<p>现在时间时: {{ moment().format('YYYY年M月D日, h:mm:ss a') }}.</p>
<p>已经过去了: {{ moment().fromTime(time) }}.</p>
<p>{{ moment().calendar() }}.</p>
结果:
现在时间时: 2015年4月22日, 10:06:33 上午.
已经过去了: 21年内.
今天上午10点06.
3.flask扩展之flask_login模块
这里将详细讲述flask_login模块的使用流程和机制
1.使用前首先要配置和初始化
from flask_login import LoginManager
login_manage=LoginManager()
def init_ext(app):
login_manage.init_app(app)
#这里要指定登陆函数的端口,以方便login跟踪操作
login_manage.login_view='main.login'
这个配置的是当给视图加@login_required的时候非登陆用户操作出现的message
login_manage.login_message='需要登陆才能执行此操作'
login_manage.login_message_category='info'
#设置对session的保护等级
login_manage.session_protection='strong'
2.配置完成后,我们要在模型中实现一个继承和回调
from flask_login import UserMixin
from App.extensions import login_manage
#如果不继承UserMixin是无法满足使用flask_login的条件的
class User(db.Model,UserMixin):
__tablename__='user'
id=db.Column(db.Integer,primary_key=True)
username=db.Column(db.String(10),unique=True)
password=db.Column(db.String(128))
sex=db.Column(db.Boolean,default=1)
email=db.Column(db.String(100),unique=True)
#这个回调是用来接收一个用户id的时候返回一个用户对象
#如果没有会返回None但是不会报错
@login_manage.user_loader
def load_user(uid):
return User.query.get(int(uid))
3.好了,基本配置已经完成了,现在我们来看看flask_login怎么使用
#蓝本(视图函数)当中
from flask_login import current_user,login_user,logout_user,login_required
main=Blueprint('main',__name__)
@main.route('/login/',methods=['GET','POST'])
def login():
form=Login()
if form.validate_on_submit():
u = User.query.filter(User.username==form.username.data).first()
if not u:
return '用户不存在'
elif not u.password==form.password.data:
return '密码输入有误'
#直接通过此方法可以实现用户的登入,其实就是将用户的id存到session当中
login_user(u)
#如果需要实现记住我,请在form表单里添加相关字段
return render_template('success.html')
return render_template('login.html',form=form)
@main.route('/logout/',methods=['GET','POST'])
def logout():
#此函数的作用是实现用户的登出,其实就是从session中删除用户的id
logout_user()
return redirect(url_for('main.main_s'))
@main.route('/picture/')
#此装饰器限制的是一些只有登陆才能进行的操作,如果没有登陆,会重定向到用户登陆页面
#同时将提示信息存入flash当中
@login_required
def picture():
return render_template('picture.html')
picture.html中
#如果是非登陆用户执行越权限操作被传送过来,想显示相关flash内容
#这里是从消息中取出对应flash内容
{% for message in get_flashed_messages() %}
<div class="alert alert-warning alert-dismissible" role="alert" style="text-align: center;font-size: 30px">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span>
</button>
<strong>Warning!</strong>{{message}}
</div>
{% endfor %}
除此之外,还有一些非常方便的操作
1.判断是否是当前登陆用户在操作:
{% if current_user.is_authenticated %}{% end if %}
2.如果想使用当前用户的代理用户
from flask_login import current_user
会得到当前用户对象的代理对象,在任何地方都可以使用,类似于将用户的id从session当中取出,然后在数据库当中匹配得到对应的对象,不过这里使用的是一个代理对象
3.如果要使用真正的当前用户(比如根据当前用户搜索内容,发帖子)
u = current_user._get_current_object()
********
current_user如果此时是非登陆的用户,那么它代表的就是一个
<flask_login.mixins.AnonymousUserMixin object at 0x000001F00664BF28>
一个匿名用户对象
如果此时是登陆用户:
那么它代表的就是用户本身,跟_get_current_object()表示的是一样的,是一个用户对象
<class 'App.models.user.User'>
*******
补充:
如果想在除setting之外地方获取setting的配置信息,可以使用App代理
例如:
current_app.config['UPLOADED_PHOTOS_DEST']
4.fllask_uploads模块
1.原生上传
在使用up_loads模块之前,有一个不得不提的原生上传文件的几个知识点
1.form表单里面如果不设置它会把你的请求当成get请求来处理
2.request.files得到的是一个类似字典的形式,key是你在传文件里面给定的name属性,value是你上传的文件
3.有一个很巧妙的方法:img.save(path) path要给定包含名字在内的路径,可以快速将文件保存
2.使用模块上传
from flask_uploads import UploadSet,patch_request_class,IMAGES,configure_uploads
from flask import Flask,render_template,request
from flask_script import Manager
from flask_uploads import UploadSet,IMAGES,patch_request_class,configure_uploads
import os
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 1024*1024*64 判断大小的字节数
app.config['UPLOADED_PHOTOS_DEST']=os.path.join(os.getcwd(),'static/upload')配置参数固定了,后面文件会直接上传到配置好的文件夹中
file = UploadSet('photos',IMAGES)
pthotes是图片参数,IMAGES是过滤条件
上传文件对象配置(IMAGES是过滤图片类型的)
configure_uploads(app,file)
pathch_request_class(app,size=None) 如果size为none则自动寻找MAX_CONTENT_LENGTH
(setting为最终的配置的文件app.config)
app.config['MAX_CONTENT_LENGTH']自己可以配置文件尺寸
(manager一般是放在最后,用来运行文件)
manager = Manager(app)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/upload/',method=['GET','POST'])
def upload():
img_url = None
if request.method=='POST' and 'file' in request.files:
#文件上传
fileName = file.save(request.files.get('file'))
print(fileName) 可以看到保存成功了
img_url = file.url(filename) #只要告诉名称就可以返回完整的路由地址
print(img_url)
return render_template('flask-uploads-form/form.html',img_url=img_url)
if __name__ = "__main__":
manager.run()
实际应用中可能会用到拆分,请把上传文件的配置分别拆分到extentsion和setting中
5.flask发送邮件的方法之flask_mail模块
from flask import Flask,render_template_string
from flask_script import Manager
from flask_mail import Mail,Message
import os
from threading import Thread #导入线程
app = Flask(__name__)
#这里使用的是163邮箱的服务器地址
app.config['MAIL_SERVER']=os.environ.get('MAIL_SERVER','smtp.163.com')
app.config['MAIL_USERNAME']=os.environ.get('MAIL_USERNAME','这里输入发邮件的邮箱号')
app.config['MAIL_PASSWORD']=os.environ.get('MAIL_PASSWORD','邮箱密码')
mail = Mail(app)
manager=Manager(app)
def async_send_mail(msg):
with app.app_context():
mail.send(message=msg)
@app.route('/send/')
def send_mail():
msg = Message(subject='我是主题', recipients=['[email protected]'], sender=app.config['MAIL_USERNAME'])
msg.html = render_template_string('<h1>你好,很高兴认识你</h1>')
thr = Thread(target=async_send_mail, args=(msg,))
thr.start()
return '发送成功'
if __name__ == '__main__':
manager.run()
os.environ 的含义:一个字典对象表示是的当前环境,environ是一个字符串所对应环境的映像对象
比如os.environ['HOME'],可以往里面存东西
windows:
os.environ['HOMEPATH']:当前用户主目录。
os.environ['TEMP']:临时目录路径。
os.environ[PATHEXT']:可执行文件。
os.environ['SYSTEMROOT']:系统主目录。
os.environ['LOGONSERVER']:机器名。
os.environ['PROMPT']:设置提示符。
linux:
os.environ['USER']:当前使用用户。
os.environ['LC_COLLATE']:路径扩展的结果排序时的字母顺序。
os.environ['SHELL']:使用shell的类型。
os.environ['LAN']:使用的语言。
os.environ['SSH_AUTH_SOCK']:ssh的执行路径。
注意字典的一个用法
dict1.get('a','b')有就获取a的值,没有b就是它的值
6.一个控制图片尺寸的函数
from PIL import Image
import os
def img_zoom(path,width=300,height=200,prefix='s_'):
#图片缩放处理
img=Image.open(path)
print(img.size) #获取图片大小
#重设图片的大小
img.thumbnail((width,height))
#保存图片缩放后的新图片路径(原图和缩放图片都保存)
newPath=os.path.join(os.path.split(path)[0],prefix+path.split('/')[-1])
img.save(newPath)
img_zoom('C:/Users/Administrator/Desktop/2.jpg')
7.Flask缓存之falsk_caching模块
1.安装
pip install flask_caching
2.配置
from flask_caching import Cache(注意这个导包千万不要导错)
cache=Cache(config={
'CACHE_TYPE':'simple' (也可以是redis的缓存方式)
})
cache.init_app(app)
3.再视图函数当中使用
from App.extensions import cache
@main.route('/')
@cache.cached(timeout=300)
def main_content():
cache.set('a',10)
return '存入缓存了一个数'
@main.route('/get/')
def get_cache():
print(cache.get('a'))
return 'success'
缓存的作用是提高交互效率同时可以往缓存里面存入数据
清除缓存
cache.delete('get_list') # 删除'get_list'缓存项
cache.delete_many('get_list', 'view_hello') # 同时删除'get_list'和'view_hello'缓存项
cache.delete_memoized('create_list', 5) # 删除调用'create_list'函数并且参数为5的缓存项
cache.clear() # 清理所有缓存
注意缓存模块
@cache.cached(timeout=300,key_prefix='View_%s')
timeout:过期时间
key_prefix:缓存项键值的前缀,默认为view/%s
除了装饰视图函数,cache.cached()装饰器也可以用来装饰普通函数
但是装饰普通函数必须指定明确的key_prefix参数,
@cache.memoize()与@cache.cached()的区别就是它会将函数的参数也放在缓存项的键值中
我们可以在jinjia2模板当中使用缓存
{% cache 50, 'temp' %}
<p>This is under cache</p>
{% endcache %}
这里temp就是键值对的键
在实际使用中我们可以通过这种方式获取到缓存
from flask_cache import make_template_fragment_key
key = make_template_fragment_key('temp')
这样就把缓存获取到了
如果缓存设置的是redis,那么在redis里面是可以获取到其缓存的
flask_cache_缓存的键的名字
7.flask样式之bootstrap模块
其他方面和正常使用基本一样,但是在使用继承样式的时候,一定要把块声明出来,不然样式为空
{% extends 'bootstrap/base.html' %}
{% block title %}
主题
{% endblock %}
{% block navbar %}
这里粘贴bootstrap代码
{% endblock%}
<a href="{{ url_for('main.index') }}">
如果想导入外边带验证器快速生成的表单
{% import'bootstrap/wtf.html' as wtf%}
{% block page_content %}
<div class="row">
<div class="col-md-8">.col-md-8</div>
<div class="col-md-4">{{ wtf.quick_form(form) }}</div>
</div>
{% endblock %}
8.flask快速生成轮播图
<div class="carousel-inner" role="listbox">
{% for i in range(1,3) %}
<div class="item {% if i==1 %}active{% endif %}" style="height: 400px;">
<img src="{{ url_for('static',filename='img/'+i|string+'.jpg') }}" alt="...">
<div class="carousel-caption">
...
</div>
</div>
{% endfor %}
</div>
<!-- Controls -->
<a class="left carousel-control" href="#carousel-example-generic" role="button" data-slide="prev">
<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="right carousel-control" href="#carousel-example-generic" role="button" data-slide="next">
<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
9.快速生成表单得flask_wtf模块
是一个用于表单处理的扩展库 提供了csrf 和表单验证等功能
字段类型
字段名称 | 字段说明 |
---|---|
StringField | 普通文本字段 |
SubmitField | 提交字段 |
PasswordField | 密码字段 |
HiddenField | 隐藏域 |
TextAreaField | 多行文本域字段 |
DateField | 日期字段 |
DateTimeField | 日期时间字段 |
IntegerField | 整形字段 |
FloatField | 浮点形字段 |
BooleanField | bool字段 |
RadioFIeld | 单选 |
SelectField | 下拉字段 |
FileField | 文件上传 |
验证器
验证器 | 验证器说明 |
---|---|
DataRequired | 必填 |
Length | 长度 min max |
IPAddress | ip地址 |
URL | url地址验证 |
NumberRange | 值的范围 |
EqualTo | 验证俩个字段值的是否相同 |
Regexp | 正则匹配 |
验证邮箱 |
实例
models.py
#创建表单类
from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,SubmitField
from wtforms.validators import DataRequired,Length
class Login(FlaskForm):
#参数1 为label中的内容显示
username = StringField('用户名',validators=[DataRequired(message='用户名不能为空'),Length(min=6,max=12,message='用户名在6-12位之间...')])
userpass = PasswordField('密码',validators=[DataRequired(message='密码不能为空'),Length(min=6,max=10,message='密码长度为6-10位')])
submit = SubmitField('登录')
manage.py
@app.route('/')
def index():
return render_template('index.html')
@app.route('/login/',methods=['GET','POST'])
def login():
form = Login() #实例化登录的表单类
# if request.method=='POST':
if form.validate_on_submit(): #当前表单的csrf验证通过 和数据正确 则为真
# print(request.form) #使用request获取数据
print(form.username.data) #使用表单对象获取数据
print(form.userpass.data)
return '表单提交'
return render_template('flask-wtf-form/form2.html',form=form)
if __name__ == '__main__':
manager.run()
使用bootstrap快速渲染表单
{% extends 'common/base.html' %}
{% import 'bootstrap/wtf.html' as wtf %}
{% block page_content %}
<div class="row">
<div class="col-md-8"><img src="{{ url_for('static',filename='img/meinv.jpg') }}" alt=""></div>
<div class="col-md-4">{{ wtf.quick_form(form) }}</div>
</div>
{% endblock %}
上述封装实际是完成了下面得所有效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>wtf-form</title>
</head>
<body>
<form action="" method="post">
{{ form.csrf_token }}
{{ form.username.label() }}
{{ form.username(placeholder='请输入用户名...',style='color:red;') }}
{# {{ form.username.errors }}#}
{% if form.username.errors %}
<span style="color: red;">{{ form.username.errors.0 }}</span>
{% endif %}
<br>
{{ form.userpass.label() }}
{{ form.userpass() }}
{# {{ form.userpass.errors }}#}
{% if form.userpass.errors %}
<span style="color: red;">{{ form.userpass.errors.0 }}</span>
{% endif %}
<br>
{{ form.submit() }}
</form>
</body>
</html>
10.flask之flash消息闪现得使用
flash存储消息
get_flashed_messages()获取消息
也可以在视图函数中使用得到当前存储的消息列表,get_flashed_messages()得到的是一个消息列表
导入
from flask import flash.get_flashed_message
{%extends 'common/base.html' %}
{% block page_content%}
<h1> 首页</h1>
{% endblock%}
flash:存消息
get_flashed_message 取消息
if form.username.data !='lisi':
flash('当前用户不存在')
elif form.confirm.data!=1234:
flash('密码错误')
else:
flash('欢迎{}.format(form.username.data)')
return redirect(url_for('index')) 重定向到首页
print(get_flashed_messages()) 可以查看存到flash里面的内容
(['当前用户不存在'])得到一个列表,当初flash的消息列表
return render_template('form.html',form=form)
不管成功还是失败只有只会跳到一个模板中
(login表示登陆页面,index表示首页页面)
取出的消息列表放在base里面的原因:因为每一个函数里面都有一个get_flash_message,所以存放在base里面的content block里面
在page_congtent block的上面
{% block content%}
{% for info in get_flashed_messages()%}
<p>{{info}} </p>
{% endfor %}
{% block page_content%}
{% endblock%}
{% endblock %}
flash只是为了在模板中显示出对应的提示消息。
11.flask_sqlalchemy与数据库交互的模块
1.比较表的存储引擎的区别
MyISAM
文件存储为 3个 数据,表结构,索引 MYD MYI
InnoDB
文件存储为 2个 表结构 数据和索引
- MyISAM 不支持外键
- innodb支持
- innodb支持事物 所以安全性高
- myisam不支持事物
- myisam查询效率高于innodb
- innodb用于对数据安全性较高的存储
- myisam用于对数据安全性要求不高 但是查询效率高的网站 帖子
2.字段类型
类型名称 | python类型 | 字段说明 |
---|---|---|
Integer | int | 存储整形 |
SmallInteger | int | 小整形 |
BigInteger | int | 长整形 |
Float | float | 浮点形 |
String | string | varchar类型 |
Text | string | 长文本 |
Boolean | bool | tinyint |
Date | datetime.date | 日期 |
Time | datetime.time | 时间 |
DateTime | datetime.datetime | 时间和日期 |
Enum | str | 枚举 |
可选条件
选项 | 说明 |
---|---|
primary_key | 主键 True |
index | 常规索引 True |
unique | 唯一索引 True |
nullable | 是否为空 False |
default | 默认值 |
注意:使用索引会加快查询效率,但是会减缓运行效率
数据库中不允许同名的表
3.连接数据库,创建表,完成迁移
class Config:
SECRET_KEY='asdnjasd'
SQLALCHEMY_DATABASE_URI='mysql+pymysql://root:root@localhost:3306/circle'
DEBUG=True
SQLALCHEMY_COMMIT_ON_TEARDOWN=True
SQLALCHEMY_TRACK_MODIFICATIONS=False
from flask_sqlalchemy import SQLALchemy
from flask_migrate import Migrate
db=SQLALchemy()
migrate=Migrate(db=db)
def extension_init(app):
db.init_app(app)
migrate.init_app(app)
class User(db.Model,UserMixin):
__tablename__='user'
id=db.Column(db.Integer,primary_key=True)
username=db.Column(db.String(10),unique=True)
password=db.Column(db.String(128))
sex=db.Column(db.Boolean,default=1)
email=db.Column(db.String(100),unique=True)
如果要使用迁移,需要添加迁移命令(manage.py中)
from flask_migrate import MigrateCommand
manage.add_command('db',MigrateCommand)
使用下列指令可完成迁移
python manage.py db init
python manage.py db migrate
python manage.py db upgrade
注:如果完成发现表没有更新,将model导入App的init.py文件当中
4.数据库操作语句
(1)给表中添加行
增加一条
u=User(name='liu',age=20)
db.session.add(u)
db.session.commit() 如果配置里设置了自动提交,则不用使用这个
db.session.rollback() 用于在事务当中回滚
增加多条
u1=User(...)
u2=User(....)
db.session.add_all([u1,u2])
(2)修改表中某条内容
u= User.query.get(1) #查询id为1的对象
u.username='新值'
(3)删除某个对象(注意,删除是建立在查询的基础上的)
u=User.query.get(1)
db.session.delete(u)
db.session.commit
(4)对表中内容的一些操作方法
User.query.all() 获取到所有的数据
User.query.filter()
注意filter得到的是一个查询集
User.query.filter(‘1’) 直接写默认是查询id,如果想使用条件查询:
User.query.filter(User.name==’liujie’)
User.query.offset(4) 获取偏移4之后的其他所有数据
User.query.limit(3) 只获取3条数据
User.query.first() 只查询第一条
User.query.get(10) 获取id为10的数据
User.query.filter(User.username.contains(‘l’)) 获取名字中包含l的
User.query.filter(Usr.username.like(‘%3%’)) 包含3,3只能在中间
User.query.filter(Usr.username.like(‘3%’)) 以3开头
User.query.filter(Usr.username.like(‘%3’)) 以3结尾
类似startwith和endwith