添加属性
@property
def password(self):
return self._password
@password.setter
def password(self, raw):
self._password = generate_password_hash(raw)
=========自定义上下文管理器的一种方法
上下文管理器的一种应用
class SQLAlchemy(_SQLAlchemy):
@contextmanager
def auto_commit(self, throw=True):
try:
yield
self.session.commit()
except Exception as e:
self.session.rollback()
current_app.logger.exception('%r' % e)
if throw:
raise e
========表单自定义验证,自定义验证定义了即会被自动调用
class RegisterForm(EmailForm):
nickname = StringField('昵称', validators=[
DataRequired(), Length(2, 10, message='昵称至少需要两个字符,最多10个字符')])
password = PasswordField('密码', validators=[
DataRequired(), Length(6, 20)])
def validate_email(self, field):
if User.query.filter_by(email=field.data).first():
raise ValidationError('电子邮件已被注册')
=====================
防止参数为空:用DataRequired
from wtforms.validators import DataRequired
class Base(db.Model):
__abstract__ = True #这是个基类,不想让sqlalchemy创建
create_time = Column('create_time', Integer)
status = Column(SmallInteger, default=1)
def set_attrs(self, attrs):
for key, value in attrs.items():
if hasattr(self, key) and key != 'id':
setattr(self, key, value)
配置文件中的key一定要是大写,小写会找不到
=============
返回json字符串可以用jsonify
static_url_path: 访问静态资源的url前缀
当装饰器和请求方式完全相同时,那么执行的是第一个,如果装饰器相同但是请求方式不相同,那么它们将是独立的个体
# 通过url_map可以查看整个flask中的路由信息
print(app.url_map)
路由中参数类型:
示例:@app.route("/goods/<int:goods_id>")
定义自己的类型转换器:https://mp.weixin.qq.com/s/eyfuFdOcMJiEuCAWGNpLag
from werkzeug.routing import BaseConverter
class MobileConverte(BaseConverter)
request对象中保存了一次HTTP请求的一切信息
postman 下载地址: https://www.getpostman.com/downloads/
当我们从前端发送的数据如果是表单的数据就可以直接从form里面进行提取,如果不是表单数据那我们无法form中提取东西,我们只能从data当中去提取请求体当中的数据
http://127.0.0.1:5000/post?city=hunan url中的参数通过request.args.get("city")得到
上传文件主要用了request当中属性files
abort函数:它可以终止视图函数的执行并且还可以返回给前端特定的信息,若传递状态码则,必须是http标准状态码
自定义错误处理方法 :@app.errorhandler(404)
通过元组的形式,返回自定义的响应信息
除了一些规定的状态码,我们也可以返回自定义的状态码
app.route("/index")
def index():
resp = make_response("index page")
resp.status = "666"
resp.headers["city"] = "hn"
# 设置cookie
resp.set_cookie("Itcast", "python")
return resp
返回json数据
@app.route("/index")
def index():
data = {
"name":"javaandpython",
"age":20
}
return jsonify(data)
jsonify不仅可以帮我们把字典转为json格式,还能帮我们把响应头中的Content-Type设置为application/json
cookie的默认有效期是临时cookie,浏览器关闭就会失效
resp.set_cookie("Itcast", "python", max_age=3600) 通过max_age设置有效期单位是秒
获取cookie:c = request.cookies.get("Itcast")
删除cookie
@app.route("/delete_cookie")
def delete_cookie():
resp = make_response("del success")
resp.delete_cookie()
return resp
其实在删除cookie当中,并不是真正的删除,只是把当前需要删除的cookie的有效期设置为了创建时候的时间,所以相当于是删除了cookie
在Flask当中如果我们需要使用session,那么我们必须配置app当中的SECRET_KEY参数,否则程序会报错。参数的值我们可以任意编写
app.config["SECRET_KEY"] = "123FIISUODFNOSAIFNHASIJDdasd"
request:封装了HTTP请求的内容,针对的是http请求。举例:user = request.args.get('user'),获取的是get请求的参数。
session:用来记录请求会话中的信息,针对的是用户信息。举例:session['name'] = user.id,可以记录用户信息。还可以通过session.get('name')获取用户信息
利用“上下文对象”将request对象作为全局变量,此时这个request对象就是在这个线程中的全局变量。但是如果这个对象是在A线程当中那么他就是A线程中的全局变量,在其他线程(B线程,C线程...)当中不是全局变量,这样就可以保证对象不会混淆
request和session都属于请求上下文对象
current_app和g都属于应用上下文对象。
1.before_first_request : 在第一次请求之前运行,只执行一次,如链接数据库
2.before_request : 在每一次请求都会执行,可以在这里做权限校验操作,比如说某用户是黑名单用户,黑名单用户登录系统将遭到拒绝访问,可以使用before_request进行权限校验。
3.after_request :在请求之后运行,会接收一个参数,这个参数就是前面的请求处理完毕之后, 返回的响应数据,如果需要对响应做额外处理,可以再这里进行。
4.teardown_request :每一次请求之后都会调用,会接受一个参数,参数是服务器出现的错误信息
userlog 把user.id当作外键,则选要在user定义时,需要加上外键关系
class User(db.Model):
__tablename__ = "user"
__table_args__ = {"useexisting": True}
id = db.Column(db.Integer, primary_key=True) # 编号
name = db.Column(db.String(100), unique=True) # 昵称
pwd = db.Column(db.String(100)) # 密码
email = db.Column(db.String(100), unique=True) # 邮箱
phone = db.Column(db.String(11), unique=True) # 电话号码
info = db.Column(db.Text) # 个性简介
face = db.Column(db.String(255), unique=True) # 头像
addtime = db.Column(db.DateTime, index=True, default=datetime.now) # 添加时间
uuid = db.Column(db.String(255), unique=True) # 唯一标志符
userlogs = db.relationship('UserLog', backref='user') # 会员日志外键关系
comments = db.relationship('Comment', backref='user') # 评论外键关系关联
moviecols = db.relationship('MovieCol', backref='user') # 电影收藏外键关系关联
# 定义会员登录日志模型
class UserLog(db.Model):
__tablename__ = "userlog"
__table_args__ = {"useexisting": True}
id = db.Column(db.Integer, primary_key=True) # 编号
user_id = db.Column(db.Integer, db.ForeignKey('user.id')) # 所属会员
ip = db.Column(db.String(100)) # 登录IP
addtime = db.Column(db.DateTime, index=True, default=datetime.now) # 添加时间
================
在模板中的操作:
1、静态文件的引入
{{ url_for('static',filename='文件路径')}}
2、定义路由
{{ url_for('模块名.视图名',变量=参数)}}
3、定义数据块
{%block 数据块名称%} .....{% endblock %}
==================
index.html继承了home.html,index.html和home.html 在同级目录,要加上 home
{% extends "home/home.html" %} <!-- 不能写成这样 {% extends "home.html" %}-->
{% block content %} <h1>Helo,World!</h1> {% endblock %}
=============把一个页面添加到另一个页面
{% include "home/menu.html" %}
================
# 登录装饰器
def user_login_req(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if "user" not in session:
return redirect(url_for("home.login", next=request.url)) #登陆之后,跳到用户想访问的页面
return f(*args, **kwargs)
return decorated_function
====================
def login():
form = LoginForm()
if form.validate_on_submit():
data = form.data
user = User.query.filter_by(name=data["name"]).first()
if not user.check_pwd(data["pwd"]):
flash("密码错误!", "err")
return redirect(url_for("home.login"))
session["user"] = user.name
session["user_id"] = user.id
userlog = UserLog(
user_id=user.id,
ip=request.remote_addr # 获取用户的登陆地址
)
db.session.add(userlog)
db.session.commit()
return redirect(url_for("home.user"))
return render_template("home/login.html", form=form) # 是相对templates的相对地址
=============
from werkzeug.security import generate_password_hash
pwd=generate_password_hash(data["pwd"]) #密码加密
from werkzeug.security import check_password_hash
return check_password_hash(self.pwd, pwd) #密码是否与数据库中的一致
==============
if request.method == "GET": # 给它们赋初始值
===========
Response(resp, mimetype='application/json') #告诉浏览器资源的类型,浏览器根据资源类型决定如何处理服务器返回的内容
==========多表关联查询
page_data = Comment.query.join(
Movie
).join(
User
).filter(
Movie.id == movie.id,
User.id == Comment.user_id
).order_by(
Comment.addtime.desc()
).paginate(page=page, per_page=10)
==========添加多条记录
db.session.add_all(user_list)
db.session.commit()
=======跨域访问
跨域是指:浏览器A从服务器B获取的静态资源,包括Html、Css、Js,然后在Js中通过Ajax访问C服务器的静态资源或请求。即:浏览器A从B服务器拿的资源,资源中想访问服务器C的资源
pip install Flask-Cors
from flask_cors import CORS
=================
Flask-Limiter对flask的路由功能提供访问速率限制的功能。访问的信息可以存储到应用本身的内存里,或者存储到redis、memcache里
from flask_limiter import Limiter
======性能调试工具:每行代码的执行时间==========
javascript:void(0)
from line_profiler import LineProfiler
from line_profiler import LineProfiler
import random
def do_other_stuff(numbers):
s = sum(numbers)
def do_stuff(numbers):
do_other_stuff(numbers)
l = [numbers[i]/43 for i in range(len(numbers))]
m = ['hello'+str(numbers[i]) for i in range(len(numbers))]
numbers = [random.randint(1,100) for i in range(1000)]
lp = LineProfiler()
lp_wrapper = lp(do_stuff)
lp_wrapper(numbers)
这样做的话,只能显示子函数的总时间
为了能够同时显示函数每行所用时间和调用函数每行所用时间,加入add_function就能够解决
from line_profiler import LineProfiler
import random
def do_other_stuff(numbers):
s = sum(numbers)
def do_stuff(numbers):
do_other_stuff(numbers)
l = [numbers[i]/43 for i in range(len(numbers))]
m = ['hello'+str(numbers[i]) for i in range(len(numbers))]
numbers = [random.randint(1,100) for i in range(1000)]
lp = LineProfiler()
lp.add_function(do_other_stuff) # add additional function to profile
lp_wrapper = lp(do_stuff)
lp_wrapper(numbers)
lp.print_stats()
=========
@app.route("/index/") 写成这样的话,/index和/index/都能访问此视图函数
@app.route("/index") 写成这样的话,/index/是无法访问的
打开debug=TRUE模式后,后端的修改会导致flask重启,是修改立即生效
添加路由函数的另一种方法:app.add_url_rule('/index',view_func=hello) 基于类的视图需要这样添加视图函数