Flask入门知识点小结

目录

一、Flask基础

1. 基于Flask框架可快速建立起后端服务器:

app = Flask(__name__)

在主函数里运行服务器

if name = "__main__":
  app.run(debug=True, host="0.0.0.0", post="5000")
  • 127.0.0.1:回环地址,不会到达外部网络接口,ip包不离开本机
  • 0.0.0.0:代表当前设备的ip,从而外部网络可通过本机IP访问服务器

2、 实现URL与视图函数的映射

@app.route('/index', methods=["GET", "POST"])
def index():
  pass
  • 绑定url和相应的视图函数,从而用户输入url时会调用相应的视图函数

1)URL: 统一资源定位器

2)视图函数:接受客户端Web请求并给客户返回Web响应

i) 视图函数返回值

返回值可以是HTML模板、重定向网址、404错误,XML文档……

  • 返回HTML模板:通过render_template()

    from flask import ..., render_template
    ......
      return render_template("index.html")
    
  • 返回重定向网址:通过redirect()函数

    可通过url_for获取视图函数对应的url

    from flask import ..., redirect, url_for
    ......
      return redirect(url_for("auth.login"))
    
  • 返回成功或失败响应的Json文件:通过jsonify实现

    from flask import ..., jsonify
    ......
      return jsonify(a="1")
    

ii) Http协议的Web请求方式:GET、POST、PUT、DELETE

  • GET请求:
    • 通过URL来传递数据(......?name=asd)
    • 一般用于客户端从服务器获取资源
  • POST请求:
    • 一般用于客户端向服务器提交资源(表单等数据)

3)向视图函数中传递参数:三种方法

  • 在url上传递(可限制类型)
@app.route('/blog/<int:blog_id>')
def blog_detail(blog_id):
    return "您将访问的博客是:%d" % blog_id
  • GET请求、POST请求:通过request对象

    from flask import request
    request.get("a")
    request.form  # POST请求
    

4) 限制用户Web请求方式:设置methods参数

@app.route('/index', methods=["GET"])  # 只接收GET请求
def index():
  pass

3. 前端部分

1)前端基础:

  • HTML:页面内容
  • CSS:样式
    • Bootstrap库
  • JavaScript:脚本语言
    • jQuery库

2)基于Jinja2模板引擎的HTML模板

Flask底层集成了Jinja2模板引擎,因此可直接调用render_template()函数渲染模板(但实际是基于Jinja2实现的)

功能包括(传递给render_template()函数的HTML模板,还要在底层由Jinja2库进行相应操作后才发送给用户,因此可以在这里写一些HTML常规语法没有的语法功能):

i) 给HTML模板传参

可以传递给HTML模板数据(包括用户自定义的对象等)

Python中

@app.route('/blog2/<blog_id>')
def index(blog_id):
    user = User(username="asdf", email="asdf@qwe")
    return render_template("index.html", user=user) 

HTML模板中:通过双花括号传递参数、访问对象属性

<h1>您访问的博客详情是:{{ user.username }}</h1>

ii) HTML模板中使用筛选器

核心作用;可以在HTML模板中使用函数

  • 过滤器相当于一个函数,通过|调用,例如{{name|length}}即为length(name),其中length即是模板内置的函数
  • 过滤器先根据自己功能返回值,然后将该值渲染到模板页面中
模板过滤器

常用模板过滤器:

  • 字符串操作
  • 数值操作
  • 列表操作
  • 字典列表操作
自定义过滤器
  1. 先自定义过滤器函数(例如my_filter)

    def Str_Is(value):
        return "str is: " + str(value)
    
  2. 将此过滤器加给app

    第二个参数为调用时所用的名字

    app.add_template_filter(Str_Is, "Str_Is")
    
  3. 在HTML模板中调用即可

    <div>测试自定义筛选器:{{name|Str_Is}}</div>
    

iii) HTML模板中使用控制语句

条件语句(一定要加上endif作为结束标识)
{% if user_age>18 %}
<div>有18岁了</div>
{% elif user_age>16 %}
<div>有16岁了</div>
{% else %}
<div>不到16</div>
{% endif %}   
循环语句(一定要加上endfor作为结束标识)
{% for i in range(5) %}
    <div>{{ i }}</div>
{% endfor %}


{% for book in books %}
    <div>{{ book }}</div>
{% endfor %}

iv) 在HTML模板中导入静态库

由于HTML文件是发在用户浏览器端执行,因此不能直接使用服务器本地地址

通过url_for获取静态库url:

<script
     src="{{ url_for('static', filename='jQuery.js')}}">
</script>

v) HTML模板继承

为了避免对相同内容的重复书写

父模板中(block后为此block的名字,可以自行修改)

{% block title %}父模板内容{% endblock %}

子模板中:

  • 开头:{% extends "base.html" %}

  • 使用处:(根据block名调用)

    {% block title %}
    子模板内容blablbla
    {% endblock %}
    

呈现出的结果:子模板中,block间的内容相应替换为父模板

4. 程序的上下文

上下文:可理解为一种容器,对于Flask服务器,Flask中上下文保存了Flask程序运行过程中的一些信息

Flask程序中有两种上下文类型:请求上下文、应用上下文

  • 请求上下文:保存客户端与服务器交互的数据,例如
    • request:封装了Http请求内容
    • session:用于记录请求会话中的信息,例如用户信息等
  • 应用上下文:保存Flask程序运行中的一些信息,例如
    • current_app:表示当前运行程序的若干事项
    • g:服务器可用此存储变量,方便各视图函数交互

Flask基层是基于wekzeug对象实现,

  • 上下文内容都绑定在werkzeug.local.Local,从而同一个对象可实现多个线程中隔离

由于werkzeug对象可能包括多个Flask对象(?),因此在运行时维护一个栈,栈顶为当前用到的上下文相关数据

  • 在视图函数中,Flask底层会自动实现将所需上下文推入栈中

  • 在视图函数外执行操作,则需要手动对上下文进行入栈、出栈操作

    (以下两种方法都可)

    app_context = app.app_context()
    app_context.push()
    
    with app.app_context():
      pass
    

二、服务器端与数据库交互

1. 基于SQLAlchemy实现ORM映射

1)ORM映射:把数据库映射成类和对象的形式

flask_sqlalchemy实现了对一系列数据库的SQL映射(包括MySQL,sqList等),从而可以用纯python的方法操作数据库(而不用去管数据库本身的那些sql语句)

  • 表:映射为类
  • 表中的字段:映射为类中字段(Column)
  • 表中数据:以类的实例(对象)表示

2)Flask中具体应用方法

i) 连接数据库

# 设置数据库基本参数等
app.config['SQLALCHEMY_DATABASE_URI'] = ...
db = SQLAlchemy(app=app)

ii) 创建表

创建表:
class User(db.Model):  # 继承自db.Model
    __tablename__ = "user"  # 设置表名
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(100), nullable=False)
    password = db.Column(db.String(100), nullable=False)
表中关联外键方法

(有了backref,在user对象可以调用user1.articles获取全部关联的文章)

class ArticleFOR(db.Model):
    __tablename__ = "article"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(200), nullable=False)

    author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
    author = db.relationship("User", backref="articles")

iii) 数据库中的增删改查

查到->操作(add/delete/...)->提交(commit)

增加表项
user = User(username="qwe", password="asdf")
db.session.add(user)
db.session.commit()
查找表项
  • 根据id(primary_key)查找 get()函数

    user = User.query.get(1)
    
  • 根据相应属性查找 filter_by()函数

    users = User.query.filter_by(username="qwe")
    
    • 返回一个Query对象,类似数组,取:

      print(users[3].password)
      users.first()
      users.all()
      
  • 根据部分名查找(常用于搜索操作filter()函数

    q ="q"
    questions = User.query.filter(User.title.contains(q)).all()
    
删除表项
user = User.query.filter_by(username="罗贯中").first()
db.session.delete(user)
db.session.commit()
修改表项
user = User.query.filter_by(username="qwe").first()
user.username = "罗贯中"
db.session.commit()

2. 数据库迁移

目的:可以更改数据库格式的同时保留数据库原有数据信息

通过flask_migrate实现

先构建一个迁移对象(?)

migrate = Migrate(app, db)

然后在命令行中执行以下指令

flask db init: 只需做一次, 生成migration文件夹,包含一系列迁移脚本
flask db migrate -m"添加备注信息":会在version中生成一个迁移脚本
flask db upgrade: 运行迁移脚本,同步到数据库中

三、密码加密与验证

可以通过werkzeug.security实现

一个Hash加密方式:

from werkzeug.security import generate_password_hash, check_password_hash 

# 加密
generate_password_hash(password)
# 检查(返回结果为布尔值)
check_password_hash(hasuser.password, password)

四、表单验证功能

可以通过wtforms包实现,主要验证前端提交的数据是否满足一些基本要求

验证方法:

  1. 构建验证表单类 class RegisterForm(wtforms.Form):

    1. 字段值设置:构造为wtforms包中相应的类(传入参数为所选取的wtforms包内置验证器)

      email = wtforms.StringField
       (validators=[Email(message="邮箱格式错误")])
      
    2. 可自定义验证方法(会被自动调用)

      def validate_email(self, filed):
       email = filed.data  # 通过.data获取当前字段的值
       user = UserModel.query.filter_by(email=email).first()
       if user:
         raise wtforms.ValidationError(message="该邮箱已经被注册")
      
  2. 应用时,传入require.form,构造验证对象

    form = RegisterForm(request.form)
    if form.validate():  # 验证
      email = form.email.data  # 获取表单中的数据
    

常用的wtform包中工具

构造字段:

  • wtforms.StringField(validators=...)
  • wtforms.IntegerField(validators=...)

验证器:

  • Email(message="...") 验证是否为邮箱格式,message为报错信息
  • Length(min=4, max=4, message="...") 长度
  • EqualTo("password", message="...") 第一个参数要与之等的字段名
  • InputRequired(message="...") 要求必须有输入

报错信息:

  • wtforms.ValidationError(message="...")
  • 验证失败抛出异常,要记得捕获

五、发送邮件功能

可以基于flask_mail包实现

i) 构建一个用于发送邮件的Mail对象

构建对象

from flask_mail import Mail
mail = Mail()

给Mail对象添加参数

# 邮箱配置
MAIL_SERVER = "smtp.qq.com"
MAIL_USE_SSL = True
MAIL_PORT = 465
MAIL_USERNAME = "1648643704@qq.com"
MAIL_PASSWORD = "vchlffbqhdqcehdj"  # 通过开启SMPT/POP3,从而运行第三方软件进行登录
MAIL_DEFAULT_SENDER = "1648643704@qq.com"

ii) 构建邮件内容message

from flask_mail import Message
message = Message(subject="CY验证码",       # 邮件主题
                      recipients=[email],  #  邮箱地址
                      body="...")          # 邮件内容

iii) 发送邮件

mail.send(message)

六、用户登录状态:cookie与session

通过上下文session和g

1)设置登录状态:设置session参数

在flask中,session是包装在cookie中的(?,在cookie中会对其加密。

cookie:身份的象征,由服务器发给浏览器,浏览器保存,每次浏览器发送请求时附带cookie,从而证明身份

登录时设置session方法:

session['user_id'] = user.id

(设置之后服务器会发给浏览器一个cookie)

2)每次进入视图函数/模板前提取session中信息

方法:通过设置钩子函数,提取session中的信息,并在应用上下文g中加入更详细的用户信息,从而其他视图函数可以检查,若含有,则说明登录了

钩子函数

Flask框架中的一种函数,每次调用视图函数前都会先执行此函数(从而避免每次重复使用相同代码)

除了下面用到的before_request外,还有before_first_request / after_request,顾名思义

@app.before_request  # 装饰器
def my_before_request():
    user_id = session.get("user_id")  # 解密的过程flask会做好
    if user_id:  # 即
        user = UserModel.query.get(user_id)
        # setattr python内置函数
        setattr(g, "user", user)
    else:
        setattr(g, "user", None)
*上下文处理器函数

每次模板执行前都会先调用此函数,从而可以用来设置模板中登录栏的状态

@app.context_processor  
def my_context_processor():
    return {"user": g.user}  # 从而在之后所有模板中都可以使用user变量

3)对于需要登录状态的页面,需先检验

通过装饰器来重用每次的检验过程

自己编写一个用于验证登录状态的装饰器函数:

def login_required(func):
    @wraps(func)  # 为了保留函数原来的信息
    # func(1,2,c=3) ->  1,2存储到args中,c=3存储到kwargs中
    def inner(*args, **kwargs):
        if g.user:
            return func(*args, **kwargs)
        else:
            print("请先登录")
            return redirect(url_for("auth.login"))
    return inner

在每个需要登录的视图函数前应用此装饰器

@bp.route('/qa/public_question', methods=["GET", "POST"])
@login_required
def public_question():
  pass

七、客户端与服务器端交互

(如点击发送验证码功能)

1. Ajax请求

Ajax是一种用于创建快速动态网页的技术,通过后台与服务器进行少量交互,Ajax可以使网页实现异步更新(即不重新加载整个网页的情况下,对网页某部分进行更新)

Ajax工作原理:发生相应事件时,发送HTTP请求给服务器,预先绑定了回调函数,会根据服务器返回结果进行相应更新操作

(从而既完成了与服务器交互,有可根据服务器返回结果部分更新网页)

  1. 当发生需要异步更新事件时(例如用户点击了"发送邮箱验证码"按钮),客户端(浏览器)创建XMLHttpRequest对象(即一个异步调用对象)
  2. 客户端创建一个HTTP请求,会指定url、method等基础信息
  3. 绑定收到服务器相应后的状态变化函数(例如success、fail)
  4. 发送请求,获取到异步调用返回的数据
  5. 根据事先绑定的回调函数,执行相应的操作(基于JS和DOM实现局部更新)

具体应用方法(基于jQuery库的JS脚本):

  • 要求对服务器会发回来怎样的JSON数据格式及意义了解

       $.ajax({
          url: "/auth/captcha/email?email=" + email, 
          method: "GET",
          // result即后端传过来的那个json数据
          success: function (result) {  
            console.log(result);
            let code = result['code']
            // 根据返回数据进行鉴别
            if (code == 200) {
              ....
              alert("邮箱验证码已发送");
    
            } else {
              ....
              alert("系统繁忙,请稍后再次发送");
            }
          },
          fail: function (error) {
            console.log(error);
          }
        })
    
  • 服务器端需要通过jsonify等方法构造返回的json文件

    @bp.route('/captcha/email')
    def get_email_captcha():
      .....
      res = jsonify({"code": 200, "message": "", "data": None})
      return res
    

八、整体架构设计

1. 蓝图的应用

基于flask中的Blueprint包

在蓝图包blueprints包中创建蓝图

bp = Blueprint(name="auth", 
               import_name=__name__,  # 被其他包引入时的名字
               url_prefix="/auth")

蓝图中的视图函数

@bp.route('/login', methods=['GET', 'POST'])
def login():
  pass

在app.py中应用:

from blueprints.auth import bp as auth_bp
from blueprints.qa import bp as qa_bp

导入蓝图:

# 导入蓝图
app.register_blueprint(auth_bp)
app.register_blueprint(qa_bp)

在其他文件中通过url_for获取时:

url_for("qa.public_question")

2. 防止循环引用

对于db、mail,可以现在exts.py中构造,在app.py中为它们加入参数,从而可避免模型的循环引用

可以设置一个config.py文件,参数都加在这里面,然后

app.config.from_object(config)
posted @ 2023-02-25 13:07  qwer82022  阅读(248)  评论(0)    收藏  举报