zoukankan      html  css  js  c++  java
  • flask 之(四) --- 扩展|缓存|会话

    扩展 

    蓝图内置扩展 (实现的是路由的拆分)

     1 '''----------- app.py -------------'''
     2 from flask import Flask
     3 from users_views import blue1
     4 from orders_views import blue2
     5 
     6 app = Flask(__name__)
     7 
     8 # 路由注册
     9 app.register_blueprint(blueprint=blue1)
    10 app.register_blueprint(blueprint=blue2)
    11 
    12 
    13 if __name__ == '__main__':
    14     app.run()
     1 ''' ------------ users_views.py ---------------'''
     2 from flask import Blueprint
     3 # blue1 的设置(名字,导入的名字,前缀名称)
     4 blue1 = Blueprint("blue1",__name__, url_prefix="/users")
     5 
     6 # 用blue1设置路由,用前缀名字区分相同名字的路由:http://127.0.0.1:5000/users/
     7 @blue1.route("/")
     8 def index():
     9     return "用户的 Blue 信息"
    10 
    11 
    12 @blue1.route("/user/")
    13 def home():
    14     return "用户信息"
     1 ''' ----------- orders_vieews.py ----------'''
     2 from flask import Blueprint
     3 # blue2 的设置(名字,导入的名字,前缀名称)
     4 blue2 = Blueprint("blue2", __name__, url_prefix="/orders")
     5 
     6 # 用blue2设置路由,用前缀名字区分相同名字的路由:http://127.0.0.1:5000/orders/
     7 @blue2.route("/")
     8 def haha():
     9     return "订单的 blue2 信息"
    10 
    11 
    12 @blue2.route("/orders/")
    13 def ppp():
    14     return "订单信息"

    静态文件路径

    1 from flask import Flask
    2 from users_views import blue1
    3 from orders_views import blue2
    4 # 静态文件路径配置。static_folder='news/static' 是配置新的静态文件的路径
    5 app = Flask(__name__,static_folder='news/static')
    6 
    7 # 路由注册
    8 app.register_blueprint(blueprint=blue1)
    9 app.register_blueprint(blueprint=blue2)

    终端命令启动项目插件扩展:

    • 实现:flask-script
    • 安装:pip install flask-script
    • 作用:实现命令键入的方式 启动项目
    • 使用:在终端键入:python app.py runserver 
      • 查看帮助文档:  python app.py runserver --help
      • 设置指定端口:  python app.py runserver -h ip地址 -p 端口号
      • 设置自动重启:  python app.py runserver -r
      • 设置调试模式:  python app.py runserver -d
      • shell脚本调试:  python app.py shell   在终端内添加model数据
    • 配置:
     1 from flask import Flask
     2 from flask_script import Manager
     3 
     4 app = Flask(__name__)
     5 # 配置flask-script
     6 manager = Manager(app=app)
     7 
     8 @app.route('/')
     9 def hello_world():
    10     return 'Hello World!'
    11 
    12 # 使用flask-script
    13 if __name__ == '__main__':
    14     manager.run()
    15 
    16 flask-script

    对象模型迁移数据库表扩展:

    • 实现:flask-migrate
    • 安装:pip install flask-migrate -i http://pypi.douban.com/simple
    • 作用:迁移,可以自动将模型转变成数据库中的表
    • 配置:
      • 在extension.py扩展文件中绑定app和db。详见下面代码块 ;创建一个Migrate对象,传递app和db进去
      • 然后,在manage.py启动文件的manager对象上添加指令:manager.add_command("db",MigrateCommand)
    • 使用:
      • 首次使用需要初始化:           python manage.py db init
      • 如果模型有变更,生成迁移文件:python manage.py db migrate
      • 将迁移文件映射到数据库中:  python manage.py db upgrade
      • 后悔返回,回滚操作:     python manage.py db downgrade
    • extension.py
     1 from flask_migrate import Migrate
     2 from flask_sqlalchemy import SQLAlchemy
     3 
     4 db = SQLAlchemy()
     5 # 扩展文件添加配置信息。创建一个Migrate对象。
     6 migate  = Migrate()
     7 
     8 
     9 # 应用一个函数,使用函数传参数将app导入初始化
    10 def init_ext(app):
    11     db.init_app(app)
    12     migate.init_app(app,db) # 将app和db以参数的形式传递进去。注册上
    •  manage.py
    1 # 注册迁移工具命令行
    2 manager.add_command("db",MigrateCommand)
    3 
    4 if __name__ == '__main__':
    5     manager.run()
    •  未拆分写法
     1 from flask_migrate import Migrate, MigrateCommand
     2 from flask_script import Manager
     3 from app import create_app, db
     4 
     5 app = create_app()
     6 manager = Manager(app=app)
     7 
     8 # 创建迁移工具实例
     9 migrate = Migrate()
    10 migrate.init_app(app=app,db=db)
    11 
    12 
    13 # 注册迁移工具命令行
    14 manager.add_command("db",MigrateCommand)
    15 
    16 if __name__ == '__main__':
    17     manager.run()

    数据库模型和对象关系扩展

    • 实现:SQLAlchemy;                 pymysql驱动
    • 安装:pip install flask-sqlalchemy ;pip install pymysql
    • 作用:ORM(Object Relational Mapping) 对象关系映射。将数据库转为面向对象的操作,通过操作对象就可实现对数据的CRUD
    • 配置:
     1 from flask import Flask, render_template
     2 from flask_sqlalchemy import SQLAlchemy
     3 
     4 app = Flask(__name__)
     5 
     6 # 配置连接sqlite数据库的指定信息。SQLite数据库连接不需要额外驱动,也不需要用户名和密码
     7 app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///hello.sqlite'  
     8 # 设False为更好的兼容性,禁止对象追踪修改
     9 app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False              
     
    11 db = SQLAlchemy(app)                                              
    12 
    13 
    14 # 配置连接mysql数据库的指定信息。dialect+driver://username:password@host:port/database
    15 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:guoyapeng@localhost:3306/FlaskModel'
    16 app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False  
    17 db = SQLAlchemy(app) 18 19 20 if __name__ == '__main__': 21 app.run()
    • 使用:下面链接文件中的 模型板块

    https://www.cnblogs.com/TMMM/p/11450872.html


    缓存技术cache扩展库插件:

    • 实现:flask_caching
    • 安装:pip install flask-caching
    • 作用:
      • 减少磁盘IO可以大幅度提升服务器性能。
      • 数据库IO操作的是web应⽤性能的瓶颈。为了提⾼访问效率,应尽可能减少数据库的操作。
      • 可以将经常访问的数据缓存起来,再次使⽤用时直接从缓存中获取,而不是每次都操作数据库。
    • 字段
    from flask_caching import Cache
    
    cache = Cache()
    cache.init_app(app=app, config={'CACHE_TYPE': 'simple'})
     1 CACHE_REDIS_URL    # 连接到Redis服务器的URL。一键配置示例 
     2 cache = Cache(config={
     3   "CACHE_TYPE": "redis",
     4   "CACHE_REDIS_URL":"redis://:localhost@127.0.0.1:6379/1",})
     5 
     6 # 以下参数是所有的类型共有的
     7 CACHE_NO_NULL_WARNING = "warning"  # null类型时的警告消息
     8 CACHE_ARGS = []              # 在缓存类实例化过程中解包和传递的可选列表,用来配置相关后端的额外的参数
     9 CACHE_OPTIONS = {}           # 可选字典,在缓存类实例化期间传递,也是用来配置相关后端的额外的键值对参数
    10 CACHE_DEFAULT_TIMEOUT        # 默认过期/超时时间,单位为秒
    11 CACHE_THRESHOLD              # 缓存的最大条目数
    12 
    13 CACHE_TYPE:                # 设置缓存的类型
    14 CACHE_TYPE = null          # 默认的缓存类型,无缓存
    15 CACHE_TYPE = 'simple'      # 使用本地python字典进行存储,非线程安全
    16 CACHE_TYPE = 'filesystem'  # 使用文件系统来存储缓存的值
    17 CACHE_TYPE = 'memcached'   # 使用memcached服务器缓存
    18 CACHE_TYPE = 'redis'       # 使用redis作为缓存
     1 CACHE_TYPE = 'filesystem' # 使用文件系统来存储缓存的值
     2 CACHE_DIR = ""            # 文件目录
     3 
     4 CACHE_TYPE = 'memcached'  # 使用memcached服务器缓存
     5 CACHE_KEY_PREFIX          # 设置cache_key的前缀
     6 CAHCE_MEMCACHED_SERVERS   # 服务器地址的列表或元组
     7 CACHE_MEMCACHED_USERNAME  # 用户名
     8 CACHE_MEMCACHED_PASSWORD  # 密码
     9 
    10 CACHE_TYPE = 'redis'      # 使用redis作为缓存
    11 CACHE_KEY_PREFIX          # 设置cache_key的前缀
    12 CACHE_REDIS_HOST          # redis地址
    13 CACHE_REDIS_PORT          # redis端口
    14 CACHE_REDIS_PASSWORD      # redis密码
    15 CACHE_REDIS_DB            # 使用哪个数据库
    • 配置
    • manage.py
    from flask_script import Manager
    from app import create_app
    
    app = create_app()
    manager = Manager(app=app)
    
    
    if __name__ == '__main__':
        manager.run()
    • app/__init__.py
    from flask import Flask
    from app import views, ext
    
    def create_app():
        app = Flask(__name__)
    # 注册缓存配置 ext.init_cache(app) # 注册路由 app.register_blueprint(views.bp) return app
    • app/ext.py
     1 from flask_caching import Cache
     2 
     3 cache = Cache()
     4 
     5 def init_cache(app):
     6     
     7     # CACHE_TYPE = 'redis'    使用redis作为缓存
     8     # CACHE_KEY_PREFIX    设置cache_key的前缀。不设置表示默认
     9     # CACHE_REDIS_HOST    redis地址
    10     # CACHE_REDIS_PORT    redis端口
    11     # CACHE_REDIS_PASSWORD    redis密码。没密码就不用设置
    12     # CACHE_REDIS_DB  使用哪个数据库,不设置表示随机
    13     
    14     app.config["CACHE_TYPE"] = "redis"
    15     app.config["CACHE_REDIS_HOST"] = "127.0.0.1"
    16     app.config["CACHE_REDIS_PORT"] = 6379
    17     # 设置缓存到app上
    18     cache.init_app(app=app)
    • 使用
    • movies/views.py
     1 from time import sleep
     2 from app.ext import cache
     3 
     4 @user_blue.route("/learn/")
     5 @cache.cached(60) # 设置缓存,60秒有效
     6 def learn():
     7     print("开始学习")
     8     sleep(10)
     9     print("结束学习")
    10     return "缓存技术,提高学习时间"

    会话技术session扩展库插件

    • 实现:flask_session
    • 作用:实现http的长链接,用会话技术为了数据可以跨请求使用,让服务器识别客户端
    • 安装:pip install flask-session
    • 配置:
     1 import datetime
     2 from flask import Flask
     3 from flask_session import Session
     4 from app import views
     5 
     6 def create_app():
     7     
     8     app = Flask(__name__)
     9 
    10     # 为sesson设置一个密钥key值。两种方式,推荐第二种
    11     # app.secret_key = 'asdfghjkl'
    12     app.config['SECRET_KEY'] = 'd53a40dae292df9d409ef64e4a04905d'
    13 
    14     # flssk-session 扩展配置
    15     # 指定 flask-session 扩展将 session 数据持久化到 redis 中
    16     app.config['SESSION_TYPE'] = 'redis'
    17 
    18     # 指定 flask-session 存储在 redis 中的 session id的前缀
    19     app.config['SESSION_KEY_PREFIX'] = 'flask:session'
    20 
    21     # 自定义 session 过期时间
    22     app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(days=7)
    23 
    24     # 创建 flask-session 的 Session 对象
    25     sess = Session()
    26 
    27     # 将 flask-session 扩展初始化,跟app建立链接
    28     sess.init_app(app=app)
    29 
    30     app.register_blueprint(views.bp)  # 注册路由
    31     return app
    • 使用: 以下链接中的 session会话 模块

     https://www.cnblogs.com/TMMM/p/11478808.html


    管理⽤户登录登出扩展库插件:

    • 实现:flask-login
    • 安装:pip install flask-login
    • 作用:是一个专门用来管理用户登录退出的扩展库
    • 步骤:
      • 1.  在extension.py中 app上注册flask-login扩展,指定登陆页面。如下两行代码
      • 2. 在model.py中 在登陆对象(User)中继承 UserMixin类,提供便捷的功能
      • 3. 在views.py中 增加load_user回调函数,导入扩展文件包加装饰器@login_manager.user_loader。
      •     供flask-login扩展在内部加载当前登陆的用户对象。flask-login默认通过user id的方式,调用load_user函数,获得用户对象
      • 4. 登陆成功后,调用login_user(user)将登陆成功的对象绑定到session中
      • 5. 使用lagin_required装饰器,保护访问受限的视图函数
    • 配置:
      • manage.py 注册
     1 # 添加扩展
     3 from flask import Flask
     4 from flask.ext.login import LoginManager
    
     6 app = Flask(__name__)
     
     8 # 1.实例化login_manager
     9 login_manager = LoginManager()
    10 # 2.将login_manager与app绑定 11 login_manager.init_app(app)
    12 # 3.设置登录视图名称。如果未登录用户请求只有登录用户才能访问的视图,则重定向到这个设置的登录视图。 13 login_manager.login_view = 'blue.login'

    14 # 4.如果未设置登录视图,则直接返回401错误。设置登录错误信息 15 login_manager.login_message = '请登录!'
      • models.py 继承
     1 from flask_login import UserMixin
     2 from flask_sqlalchemy import SQLAlchemy
     3 
     4 db = SQLAlchemy()
     5 # 让User继承自UserMixin。
     6 class User(UserMixin,db.Model):
     7     __tablename__= "users"
     8     id = db.Column(db.Integer,primary_key=True)
     9     username = db.Column(db.String(16),unique=True,nullable=False)
    10     password = db.Column(db.String(256),unique=True,nullable=False)
      • views.py 初始化
    1 # 告诉ext.py中login_manager的用户是从哪来的。用户加载的地方
    2 @login_manager.user_loader
    3 def load_user(user_id):
    4     return User.query.get(user_id)
    • 使用
     1 """
     2 状态切换:
     3   login_user   # 登录
     4   logout_user  # 退出登录  
     5 
     6 路由保护:
     7   login_required   # 保护需要登录才能访问的路路由   
     8  
     9 当前用户:
    10   current_user     # 哪⾥都可以使⽤(在模板中不需要分配)
    11 
    12 实现回调:
    13   @login_manager.user_loader
    14   def load_user(uid):
    15    return User.query.get(uid)
    16 """
     1 #属性 is_authenticated
     2 #当用户登录成功后,该属性为True。
     3 
     4 #属性 is_active
     5 #如果该用户账号已被激活,且该用户已登录成功,则此属性为True。
     6 
     7 #属性 is_anonymous
     8 #是否为匿名用户(未登录用户)。
     9 
    10 #方法 get_id()
    11 #每个用户都必须有一个唯一的标识符作为ID,该方法可以返回当前用户的ID,这里ID必须是Unicode。
     7 <body>
     8 
     9 {# 当前用户:current_user,属性:is_authenticated 当前用户登录成功后该属性为True。 #}
    10 {# 判断用户是否登陆,如果登陆显示:用户名、注销、用户主页、关于网站。如果没有登陆显示:请登录、用户主页、关于网站 #}
    11 {% if current_user.is_authenticated %} 12 当前登陆用户为:{{ current_user.username }}<a href="{{ url_for("blue.logout") }}">注销</a> 13 {% else %} 14 <a href="{{ url_for("blue.login") }}">请登录</a> 15 {% endif %} 16 <a href="{{ url_for("blue.home") }}">用户主页</a> 17 <a href="{{ url_for("blue.about") }}">关于网站</a> 18 19 </body>
      • models.py
     1 from flask_login import UserMixin
     2 from flask_sqlalchemy import SQLAlchemy
     3 
     4 db = SQLAlchemy()
     5 
     6 class User(UserMixin,db.Model):
     7     __tablename__= "users"
     8     id = db.Column(db.Integer,primary_key=True)
     9     username = db.Column(db.String(16),unique=True,nullable=False)
    10     password = db.Column(db.String(256),unique=True,nullable=False)
      • views.py
     1 from flask import Blueprint, render_template, request, redirect, url_for, flash
     2 from flask_login import login_user, logout_user, login_required
     3 from werkzeug.security import generate_password_hash, check_password_hash
     4 from app.ext import login_manager
     5 from app.models import User, db
     6 
     7 bp = Blueprint('blue', __name__)
     8 
     9 
    10 @bp.route('/register/', methods=['GET', 'POST'])
    11 def register():
    12     if request.method == 'POST':
    13         # 处理注册逻辑。 1、检查两次输入的密码是否相等; 2、检查用户名是否重复
    14         username = request.form.get('username')
    15         password = request.form.get('password')
    16         re_password = request.form.get('re_password')
    17 
    18         # 检查两次输入的密码是否相等
    19         if password != re_password:
    20             return render_template('register.html', msg='两次输入密码不一致', username=username)
    21         # 查询数据库中是否有重复的用户名。 .count() 获得查询语句匹配到的行数
    22         if User.query.filter_by(username=username).count() > 0:
    23             return render_template('register.html', msg='用户名重复', username=username)
    24 
    25         # 对 password 进行加密。进行存储准备
    26         password_hash = generate_password_hash(password)
    27         user = User()
    28         user.username = username
    29         user.password = password_hash
    30         # 对新注册的用户进行存储
    31         db.session.add(user)
    32         db.session.commit()
    33 
    34         # flash 闪现消息,可以跨请求传递消息,不跨请求时也可以使用
    35         # 本质上:内部会把消息保存到 session中,在下一个请求中通过session获取
    36         """
    37         在 html 中使用
    38         {% for message in get_flashed_messages() %}
    39         {{ message }}
    40         {% endfor %}
    41         """
    42         flash('注册成功,请登录')
    43         return redirect(url_for('blue.login'))
    44     return render_template('register.html')
    45 
    46 @bp.route("/login/",methods=["POST","GET"])
    47 def login():
    48     if request.method == "POST":
    49         # 处理登陆业务
    50         username = request.form.get("username")
    51         password = request.form.get("password")
    52 
    53         user = User.query.filter_by(username=username).first()
    54         if user is None:
    55             return render_template("login.html",msg="用户或密码错误",username=username)
    56         if check_password_hash(user.password,password):
    57 
    58             # 登陆成功以后需要将登陆状态保存到session中session['uid']=user.id,使用flask-login的login_user()来完成
    59             login_user(user)
    60 
    61             # 即使是post请求,也可以用args获取跳转链接next的参数值,http://127.0.0.1:5000/login/?next=%2Fhome%2F
    62             next_url = request.args.get("next")
    63             # 如果存在 next 跳转参数,则跳转到 next 页面;否则调转到首页
    64             return redirect(next_url or url_for("blue.index"))
    65         else:
    66             return render_template("login.html", msg="用户或密码错误", username=username)
    67     return render_template("login.html")
    68 
    69 # 保护页面。需要配置默认调转页面
    70 # 使用装饰器:@login_required 实现:只有登陆的用户,点击home时页面才会看到信息;没有登陆的用户点击会被跳转到登陆页面
    71 @bp.route("/home/")
    72 @login_required
    73 def home():
    74     return "home"
    75 
    76 # 登出操作。用 flask-login的logout_user()自动完成登出时session的清理工作
    77 @bp.route("/logout/")
    78 def logout():
    79     logout_user()
    80     return redirect(url_for("blue.index"))
    81 
    82 # 告诉ext.py中login_manager的用户是从哪来的。用户加载的地方
    83 @login_manager.user_loader
    84 def load_user(user_id):
    85     return User.query.get(user_id)
    86 
    87 
    88 @bp.route("/about/")
    89 def about():
    90     return "about"
    91 
    92 @bp.route('/')
    93 def index():
    94     return render_template('index.html')
    views.py

     表单验证模块扩展库插件:

    • 实现:flask-wtf
    • 作用:是flask框架的表单验证模块。可以很方便生成表单验证表单的数据。CSRF、字段校验等功能。
    • 安装:pip install flask-wtf
    • 注意:如果使用form提交的话,自动将form.py中的属性和html中的同名元素匹配,html中需要注明 {{ form.csrf_token }}
      • form.py中的 username = StringField(...)匹配 .html中的  <input name="username">

    • 字段

         

      SelectField:下拉框内容在 form 表单类初始化时即确定。运行中修改不生效(验证时会出错)

      QuerySelectField:下拉框内容可以动态从数据库中获取,query_factory指定查询接口

    • 配置:
      • form.py
     1 from flask_wtf import FlaskForm
     2 from wtforms import StringField, PasswordField
     3 from wtforms.validators import DataRequired, Length, EqualTo
     4 
     5 
     6 class RegisterForm(FlaskForm):
     7     # 定义页面中显示的字段标签。username是StringField类型
     8     username = StringField(
     9         # label标签 显示:"用户名"
    10         label='用户名',
    11         # 验证器:列表类型。
    12         validators=[
    13             # DataRequired 必填信息
    14             DataRequired(message='用户名为必填')
    15         ]
    16     )
    17     password = PasswordField(
    18         label='密码',
    19         validators=[
    20             DataRequired(message='密码为必填'),
    21             # 长度验证(最小2,最长4)
    22             Length(min=2, max=4, message='密码长度为 2 ~ 4'),
    23         ]
    24     )
    25     password_confirm = PasswordField(
    26         label='重复密码',
    27         validators=[
    28             # EqualTo验证和谁相等(要比较的变量)
    29             EqualTo('password', message='两次输入的密码必须一致'),
    30         ]
    31     )
    32 
    33 
    34 class LoginForm(FlaskForm):
    35     username = StringField(
    36         label='用户名',
    37         # 默认值:空
    38         default='',
    39         validators=[
    40             DataRequired(message='用户名为必填')
    41         ]
    42     )
    43     password = PasswordField(
    44         label='密码',
    45         validators=[
    46             DataRequired(message='密码为必填'),
    47         ]
    48     )
    • 使用:
      • views.py
     1 from flask import Blueprint, render_template, request, redirect, url_for
     2 from flask_login import login_user
     3 from werkzeug.security import generate_password_hash, check_password_hash
     4 from app.ext import login_manager
     5 from app.form import RegisterForm, LoginForm
     6 from app.models import User, db
     7 
     8 bp = Blueprint('blue', __name__)
     9 
    10 
    11 @bp.route('/form/register/', methods=['GET', 'POST'])
    12 def register_form():
    13     form = RegisterForm()
    14     # 普通写法:
    15     # if request.method == 'POST':
    16     #     username = request.form.get('username')
    17 
    18     # form写法
    19     # validate_on_submit 内部做了三件事
    20     # 1、判断 request.method 是否为 POST, PUT, PATCH, DELETE
    21     #    相当于 if request.method == 'POST'
    22     # 2、将表单中的同名元素自动绑定到form中的同名属性中
    23     #    相当于 username = request.form.get('username')
    24     #         form.username = username
    25     # 3、验证表单数据,根据表单字段中定一个的 validators
    26     if form.validate_on_submit():
    27         # 前端数据在form验证通过后,从form获取前端传入的数据
    28         print(form.data)
    29         username = form.username.data
    30         password = form.password.data
    31 
    32         password_hash = generate_password_hash(password)
    33 
    34         user = User()
    35         user.username = username
    36         user.password = password_hash
    37 
    38         db.session.add(user)
    39         db.session.commit()
    40         return redirect(url_for('blue.login_form'))
    41     return render_template('register_form.html', form=form)  # 返回form对象数据
    42 
    43 
    44 @bp.route('/form/login/', methods=['POST', 'GET'])
    45 def login_form():
    46     form = LoginForm()
    47 
    48     # validate_on_submit 内部做了三件事
    49     # 1、判断 request.method是否为POST, PUT, PATCH, DELETE
    50     #    相当于 if request.method=='POST'
    51     # 2、将表单中的同名元素自动绑定到form中的同名属性中
    52     #    相当于 username = request.form.get('username')
    53     #         form.username = username
    54     # 3、验证表单数据,根据表单字段中定一个的 validators
    55     if form.validate_on_submit():
    56         username = form.username.data
    57         password = form.password.data
    58 
    59         # 先根据用户名查询数据库中是否有该数据
    60         user = User.query.filter_by(username=username).first()
    61 
    62         if user is None:
    63             # 如果查询的对象不存在。手工向form.username.errors追加一条错误信息,通过form显示到前端页面
    64             form.username.errors.append('用户或密码错误')
    65             return render_template('login_form.html', form=form)
    66 
    67         if check_password_hash(user.password, password):
    68             # 如果密码验证通过。使用flask-login的login_user()完成保存登陆状态的工作
    69             # 登录成功以后,需要将登录状态保存到session中,比如:session['uid']=user.id
    70             login_user(user)
    71 
    72             # 获得跳转连接,如果url中存在next跳转参数,则跳转到next页面,否则跳转到首页
    73             # 通过args获取post请求中的URL的next参数信息
    74             next_url = request.args.get('next')
    75             return redirect(next_url or url_for('blue.index'))
    76         else:
    77             form.password.errors.append('用户或密码错误')
    78             return render_template('login_form.html', form=form)
    79     return render_template('login_form.html', form=form)
    80 
    81 
    82 @bp.route("/form/index/",methods=['POST','GET'])
    83 def index():
    84     return render_template("index.html")
    85 
    86 @login_manager.user_loader
    87 def load_user(user_id):
    88     return User.query.get(user_id)
     1 # 修改资源
     2 @app.route('/article/<article_id>/change/', methods=['POST', 'GET'])
     3 def article_change(article_id):
     4     article = Article.query.get(article_id)
     5     # 根据 数据库中查询到的数据 创建 Form 对象
     6     # ArticleForm 内部会 将 article 对象的同名属性设置到 ArticleForm 的同名属性上
     7     # form.title = article.title
     8     # form.content = article.content
     9     # form.title.data
    10     form = ArticleForm(obj=article)
    11     if form.validate_on_submit():
    12         # 使用表单对象的 populate_obj 方法,用已验证表单的内容来填充 Article 对象
    13         # 将表单中提交过来的内容,再次反向绑定form上去
    14         # article.title = form.title.data
    15         # article.content = form.content.data
    16         form.populate_obj(article)
    17         db.session.commit()
    18 
    19         flash('文章保存成功')
    20         return redirect(url_for('blue.article_list'))
    21     return render_template('article-change.html', form=form)
    修改资源
      • login_form.html
     1 <body>
     2 <form action="{{ url_for("blue.index") }}" method="post">
     3     {# <跨域访问></防跨域访问> #}
     4     {{ form.csrf_token }}
     5                              {# 登陆验证失败后: <重新显示输入的信息>   </返回错误原因>  #}
     6     用户名:<input name="username" type="text" value="{{ form.username.data }}">{{ form.username.errors }}
     7     密码:<input name="password" type="password" value="">{{ form.password.errors }}
    10     <input type="submit" value="submit">
    11 </form>
    12 </body>
      • register.html
     1 <body>
     2 <form action="" method="post">
     3     {# <csrf防跨域访问></csrf防跨域访问> #}
     4     {{ form.csrf_token }}
     5     {# flask-wtf 写法 #}
     6     {{ form.username.label }} {{ form.username() }} {{ form.username.errors }}
     7     {{ form.password.label }} {{ form.password }} {{ form.password.errors }}
     8     {{ form.password_confirm.label }} {{ form.password_confirm }} {{ form.password_confirm.errors }}
     9     <input type="submit" value="submit">
    10 </form>
    11 </body>

    缓存技术

    方法

    """
    cache.cached:装饰器,装饰无参数函数,使得该函数结果可以缓存
    参数:
        timeout:       超时时间
        key_prefix:    设置该函数的标志
        unless:        设置是否启用缓存,如果为True,不启用缓存
        forced_update: 设置缓存是否实时更新,如果为True,无论是否过期都将更新缓存
        query_string:  为True时,缓存键是先将参数排序然后哈希的结果
          
    cache.memoize:装饰器,装饰有参数函数,使得该函数结果可以缓存
    参数:
       make_name:设置函数的标志,如果没有就使用装饰的函数
       其他参数同cached
    
    cache.delete_memoized:删除缓存
    参数:
       func_name:缓存函数的引用
       *args:函数参数
    """
    # cache.clear()  # 清除缓存所有的缓存,这个操作需要慎重
    # cache.get(key)  # 获取一个键的值,如果值是json格式会自动转化成字典
    # cache.set(key,value,timeout)      #设置一个键值,value可以是字典,会自动转化json格式的字符串
    # cache.add(key, value, timeout=None)  #设置一个键值,如果存在就pass,注意和set的区别
    # cache.delete(key)  #删除键

    流程

      

    使用 

    • app/views.py
     1 import random
     2 import time
     3 from flask import Blueprint
     4 from app.ext import cache
     5 
     6 bp = Blueprint("blue",__name__)
     7 
     8 # 缓存视图函数 设置缓存。过期时间10秒
     9 @bp.route("/cache_views/")
    10 @cache.cached(timeout=10)
    11 def cache_views():
    12     """
    13     当通过 cache.cached 缓存视图函数时,
    14     在超时之前(timeout<10)访问此视图函数,会先去去缓存中查找,返回缓存中的数据。
    15     在超时之后(timeout>10)访问此视图函数,会去缓存中查找,查不到再去数据库中查找,后保存在缓存中并返回数据。
    16     :return: 例如:网站首页,不经常变化的话,可以将其存到缓存中
    17     """
    18     now = time.time()
    19     return str(now)
    20 
    21 
    22 # 缓存普通函数(单独缓存某个函数,提供更好的复用性)
    23 # 推荐指定key_prefix,缓存key的前缀。否则key为调⽤的视图函数所在的路由
    24 @cache.cached(timeout=30, key_prefix='random_list')
    25 def random_list():         # 随机提取十个数字
    26     return [random.randint(0, 100) for _ in range(10)]
    27 
    28 @bp.route('/random_view/')
    29 def random_view():
    30     list0 = random_list()  # 获取缓存中的十个数据
    31     list1 = ",".join(map(str,list0))
    32     list2 = list1 + "------>" + str(random.randint(0, 100))
    33     return list2
    34 
    35 
    36 # 缓存带参函数
    37 @cache.memoize(timeout=30,make_name="random_parm")
    38 def random_parm(arg1, arg2):
    39     return arg1 + arg2 + random.randint(0,10)
    40 # 根据参数值 随机获取数值。参数不同 获得的随机数不同,且互不影响 41 # http://127.0.0.1:5000/random_args/1/3/ 结果:4----->73 42 # http://127.0.0.1:5000/random_args/1/2/ 结果:6----->48 43 @bp.route("/random_args/<int:arg1>/<int:arg2>/") 44 def random_args(arg1,arg2): 45 return str(random_parm(arg1,arg2)) + "----->" + str(random.randint(0,100))
    46 # 清理缓存。cache.delete(函数名,此函数参数,此函数参数) 47 @bp.route("/delete/<int:arg1>/<int:arg2>") 48 def delete(arg1,arg2): 49 cache.delete(random_parm,arg1,arg2) 51 return "ok" 52 53 54 # 缓存对象(键值对)。cache.set('键', '值', 过期时间) 55 @bp.route("/set_cache/") 56 def set_cache(): 57 cache.set('name', '老王', timeout=30) 58 cache.set('persion', {'name': '晓黎', 'age': 18}, timeout=30) 59 cache.set('lst', [1, 2, 3, 4], timeout=30) 60 # 模拟登录成功后,把用户身份信息保存到 session 61 session_id = '987654321' 62 cache.set(session_id, {'user_id': 123456}, timeout=1800) 63 64 print(cache.get('name')) 65 print(cache.get('persion')) 66 print(cache.get('lst')) 67 # 模拟 根据 session_id 获取用户的身份信息 68 print(cache.get(session_id)) 69 70 return "ok"

    会话技术(cookie)

     出现原因:HTTP是无状态协议,使用的短连接,请求周期非常短。使用会话技术为了数据可以跨请求使用,让服务器识别客户端

     Cookie:Cookie客户端会话技术,数据都存储在浏览器中,默认携带本网站的所有Cookie。缺点:明文传输不安全

          Cookie以key-value存储,支持过期,默认关闭浏览器即失效;不能跨浏览器,不能跨域名访问

     

    • manage.py
    1 from flask_script import Manager
    2 from app import create_app
    3 
    4 app = create_app()         
    5 manager = Manager(app=app)  
    6 
    7 if __name__ == '__main__':
    8     manager.run()
    • app/__init__.py
    1 from flask import Flask
    2 from app import views
    3 
    4 def create_app():
    5     app = Flask(__name__)            # 实例化 Flask对象
    6     app.register_blueprint(views.bp) # 将蓝图注册到app上
    7     return app                       # 返回出去 Flask实例
    • app/views.py
     1 from flask import Blueprint, request, render_template, make_response, redirect, url_for, abort
     2 
     3 # 用蓝图管理路由,规划url。参数("蓝图名字",__name__)
     4 # 蓝图必须了管理的视图在一个文件中,不然不能使用
     5 bp = Blueprint("blue",__name__)
     6 
     7 @bp.route('/index')
     8 def index():
     9     username = request.cookies.get('username','游客')
    10     return render_template("index.html",username= username)
    11 
    12 @bp.route('/login/',methods=['GET','POST'])
    13 def login():
    14     if request.method == "POST":
    15         username = request.form.get('username')
    16         # 模拟登陆。使用redirect 来获取响应对象。
    17         response = redirect(url_for('blue.index'))
    18         # 通过response对象设置cookie
    19         response.set_cookie('username',username)
    20         return response
    21     # render_template(模版名称,**context) **context是需要传递到模版中的 变量
    22     return render_template('login.html')
    23 
    24 @bp.route('/logout/')
    25 def logout():
    26     # 模拟登陆,使用redirect 来获取响应对象。
    27     response = redirect(url_for('blue.index'))
    28     # 删除cookie
    29     response.delete_cookie('username')
    30     return response
    • app/templates/index.html
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>index</title>
     6 </head>
     7 <body>
     8 <h2>欢迎:{{ username }}</h2>
     9 <form action="{{ url_for('blue.logout')}}" method="get">
    10     <input type="submit" value="登出">
    11 </form>
    12 </body>
    13 </html>
    • app/templates/login.html
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Title</title>
     6 </head>
     7 <body>
     8 <form action="{{ url_for('blue.login')}}" method="post">
     9     <input type="text" name="username" value="" placeholder="请输入用户名">
    10     <input type="submit" value="登录">
    11 </form>
    12 </body>
    13 </html>

    会话技术(session)

     Session:服务端会话技术,数据都存储在服务端

      1、当浏览器第一次访问 web 服务器时,web 服务器会为此浏览器生成一个 session,为这个 session 创建一个唯一的 session_id;

      2、在服务器返回请求时,会向浏览器设置 cookies,cookies 中是 key-value 存储reseponse.set_cookies('session_id', session_id, expire=)

      3、浏览器再次访问此 web 服务器时,会在请求中带上 cookies 信息,即:session_id: dsfksdlfj232wrwdsf 

      4、当 web 服务器在次接收到浏览器请求时,会从请求的 cookies 中提取 session_id 的值,

         然后根据 session_id 的值,查找到与当前浏览器匹配的 session(比如:从数据库查询等)

     绘画特性:依赖于Cookie,以key-value存储、相对安全、不能跨网站,不能跨域名、支持过期默认31天 -> 设置:session.permanent = True

       

    • manage.py
    from flask_script import Manager
    from app import create_app
    
    app = create_app()
    manager = Manager(app=app)
    
    if __name__ == '__main__':
        manager.run()
    • app/__init__.py
    import datetime
    from flask import Flask
    from flask_session import Session
    from app import views
    
    def create_app():
        
        app = Flask(__name__)
    
        # 为sesson设置一个密钥key值。两种方式,推荐第二种
        # app.secret_key = 'asdfghjkl'
        app.config['SECRET_KEY'] = 'd53a40dae292df9d409ef64e4a04905d'
    
        # flssk-session 扩展配置
        # 指定 flask-session 扩展将 session 数据持久化到 redis 中
        app.config['SESSION_TYPE'] = 'redis'
    
        # 指定 flask-session 存储在 redis 中的 session id的前缀
        app.config['SESSION_KEY_PREFIX'] = 'flask:session'
    
        # 自定义 session 过期时间
        app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(days=7)
    
        # 创建 flask-session 的 Session 对象
        sess = Session()
    
        # 将 flask-session 扩展初始化,跟app建立链接
        sess.init_app(app=app)
    
        app.register_blueprint(views.bp)  # 注册路由
        return app
    • app/views.py
    from flask import Blueprint, render_template, redirect, url_for, request, session
    
    # Blueprint: 第一个参数为蓝图自定义名称,第二个参数是 Blueprint 对views.py 导入时需要的名称。
    bp = Blueprint('blue',__name__)
    """
    在 flask 项目中使用 session
    1. 为 flask 对象(app)设置secrt key
    2、在任何视图函数中都可以像使用字典一样操作 session
        session['username'] = 'jack'   向session中增加一个 键值对
        session.get('username')        从session中根据key获取value
        session.pop('username')        从session中删除指定的key
    """
    @bp.route('/index/')
    def index():
        # session.get 从 session 中根据key获取对用的值。可以像字典一样操作
        username = session.get('username','游客')
        return render_template('index.html',username=username)
    
    @bp.route('/login/',methods=["POST","GET"])
    def login():
        if request.method == 'POST':
            username = request.form.get('username')
            session['username'] = username
            return redirect(url_for('blue.index'))
        return render_template('login.html')
    
    @bp.route('/logout/')
    def logout():
        session.pop('username')
        return redirect(url_for('blue.index'))
    1 # 设置退出,
    2 @app.route('/logout/')
    3 def logout():
    4     response = Response('退出成功')
    5     response.delete_cookie('session')  # 删除session中的session参数
    6     session.pop['username']            # 删除session中的username参数值 推荐
    7     del session['username']            # 删除session中的username参数值 不存在,会报错
    8     return response
    • app/templates/login.html
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Title</title>
     6 </head>
     7 <body>
     8 <form action="{{ url_for('blue.login')}}" method="post">
     9     <input type="text" name="username" value="" placeholder="请输入用户名">
    10     <input type="submit" value="登录">
    11 </form>
    12 </body>
    13 </html>
    • app/templates/index.html
     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>Title</title>
     6 </head>
     7 <body>
     8 <h2>欢迎:{{ username }}</h2>
     9 <form action="{{ url_for('blue.logout')}}" method="get">
    10     <input type="submit" value="登出">
    11 </form>
    12 </body>
    13 </html>
    生如逆旅 一苇以航
  • 相关阅读:
    Android Studio no debuggable applications解决方案2
    Android CountDownTimer倒计时器的使用
    git 创建分支并切换
    com.android.org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: current time:
    为什么调用 FragmentPagerAdapter.notifyDataSetChanged() 并不能更新其 Fragment
    Android 使WebView支持HTML5 Video(全屏)播放的方法
    使用retrofit注意
    解决 Android Studio 乱码问题
    Android视觉规范-间距规范与文字规范单位换算(dip、sp与px)
    教你如何删除WIN7系统文件以及无法删除的文件
  • 原文地址:https://www.cnblogs.com/TMMM/p/11478808.html
Copyright © 2011-2022 走看看