flask 杂记2
添加属性
@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)
通过元组的形式,返回自定义的响应信息
除了一些规定的状态码,我们也可以返回自定义的状态码
通过make_response 设置返回内容
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()
=======跨域访问
https://www.cnblogs.com/anxminise/p/9814326.html
跨域是指:浏览器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
======性能调试工具:每行代码的执行时间==========
https://blog.csdn.net/guofangxiandaihua/article/details/77825524
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)
这样做的话,只能显示子函数的总时间 ———————————————— 版权声明:本文为CSDN博主「红色未来」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/guofangxiandaihua/article/details/77825524
为了能够同时显示函数每行所用时间和调用函数每行所用时间,加入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) 基于类的视图需要这样添加视图函数