Flask框架学习笔记_2

JinJa2模板

  • Jinja2官方文档

  • 模板基本语法:

    {% if user %}
        {{ user }}
    {% else %}
        hello!
    <ul>
        {% for index in indexs %}
        <li> {{ index }} </li>
        {% endfor %}
    </ul>
    
  • Flask中,用render_template()来渲染模板

    • return render_template('index.html')
      # 可以在里面传变量
      return render_template('index.html', name='fxh', age=21)
      
    • 也可以像 Django 一样传变量,但需要用 **

      data = {
              "name": "python",
              "age": 18,
              "my_dict": {"city": "sz"},
              "my_list": [1, 2, 3, 4, 5],
              "my_int": 0
          }
          return render_template("index.html", **data)
      
  • Flask 中,模板变量可以进行加减运算的

    <body>
        <p>name = {{ name }}</p>
        <p>age = {{ age }}</p>
        <p>my_dict: city= {{ my_dict["city"] }}</p>
        <p>my_dict: city= {{ my_dict.city }}</p>
        <p>my_list: {{ my_list }}</p>
        <p>my_list[my_int]: {{ my_list[my_int] }}</p>
        <p>my_list[0] + my_list[1] = {{ my_list[0] + my_list[1] }}</p>
        <p>{{"hello" + " python" }}</p>
    </body>
    

过滤器

  • 过滤器的本质就是函数。有时候我们不仅仅只是需要输出变量的值,我们还需要修改变量的显示,甚至格式化、运算等等,这就用到了过滤器

  • 使用方法:{{ ‘hello’ | 过滤器名}}

  • 字符串过滤器:

    过滤器功能
    safe禁用转义—>可以防止xss攻击
    capitalize首字母大写,其余字母小写
    lower把值转成小写
    upper把值转成大写
    title把值中的每个单词的首字母都转成大写
    trim把值的首尾空格去掉
    reverse字符串反转
    format格式化输出
    striptags渲染之前把值中所有的HTML标签都删掉

    过滤器可以叠加使用,{{ 'hello' | trim | upper }}

  • 列表过滤器:

    过滤器功能
    first取第一个元素
    last取最后一个元素
    length获取列表长度
    sum列表求和
    sort列表排序
  • 自定义过滤器

    • 法一:通过 add_template_filter (过滤器函数, 模板中使用的过滤器名字)

      def filter_double_sort(ls):
          return ls[::2]
      app.add_template_filter(filter_double_sort, 'double_2')
      
    • 法二:通过装饰器 app.template_filter (模板中使用的装饰器名字)

      @app.template_filter('db3')  # db3为过滤器名
      def filter_double_sort(ls):
          return ls[::-3]
      

表单

  • 表单HTML页面中负责数据采集的部件。表单有三个部分组成:表单标签、表单域、表单按钮。表单允许用户输入数据,负责HTML页面数据采集,通过表单将用户输入的数据提交给服务器。

  • 不使用Flask-WTF时,我们还需要自己去处理表单

    from flask import Flask,render_template,request
    
    @app.route('/login',methods=['GET','POST'])
    def login():
        if request.method == 'POST':
            username = request.form['username']
            password = request.form['password']
            print username,password
        	return 'success'
    	else:
            pass
    
  • 使用Flask-WTF 表单扩展,可以帮助进行CSRF验证,帮助我们快速定义表单模板,而且可以帮助我们在视图中验证表单的数据

  • 安装:pip install Flask-WTF

  • WTForms支持的HTML标准字段

    字段对象说明
    StringField文本字段
    TextAreaField多行文本字段
    PasswordField密码文本字段
    HiddenField隐藏文本字段
    DateField文本字段,值为datetime.date格式
    DateTimeField文本字段,值为datetime.datetime格式
    IntegerField文本字段,值为整数
    DecimalField文本字段,值为decimal.Decimal
    FloatField文本字段,值为浮点数
    BooleanField复选框,值为True和False
    RadioField一组单选框
    SelectField下拉列表
    SelectMultipleField下拉列表,可选择多个值
    FileField文本上传字段
    SubmitField表单提交按钮
    FormField把表单作为字段嵌入另一个表单
    FieldList一组指定类型的字段
  • WTForms常用验证函数

    验证函数说明
    DataRequired确保字段中有数据
    EqualTo比较两个字段的值,常用于比较两次密码输入
    Length验证输入的字符串长度
    NumberRange验证输入的值在数字范围内
    URL验证URL
    AnyOf验证输入值在可选列表中
    NoneOf验证输入值不在可选列表中

表单模型类

  • 定义表单模型类

    #导入wtf扩展的表单类
    from flask_wtf import FlaskForm
    #导入自定义表单需要的字段
    from wtforms import SubmitField,StringField,PasswordField
    class RegisterForm(Flask Form):
        '''自定义注册表单类,文本字段、密码字段、提交按钮'''
       # DataRequired 保证数据必须填写,并且不能为空
        user_name = StringField(label=u"用户名", validators=[DataRequired(u"用户名不能为空")])
        pw = PasswordField(label=u"密码", validators=[DataRequired(u"密码不能为空")])
        pw2 = PasswordField(label=u"确认密码", validators=[DataRequired(u"确认密码不能为空"),
                                                             EqualTo("password", u"两次密码不一致")])
        submit = SubmitField(label=u"提交")
    

    label:名字,validators:验证器,DataRequired(u'用户名不为空')传的参数为提示信息

  • 使用

    @app.route('/register')
    def register():
        # 创建表单对象,如果是post请求,前端发送了数据,flask会把数据在构造form对象的时候,存放到对象中
    	form = RegisterForm()
        # 判断form中的数据是否合理
        # 如果form中的数据完全满足所有的验证器,则返回真,否则返回假
        if form.validate_on_submit():
            # 表示验证合格
            # 提取数据
            uname = form.user_name.data
            pwd = form.password.data
            pwd2 = form.password2.data
            print(uname, pwd, pwd2)
            session["user_name"] = uname
            return redirect(url_for("index"))
    
        return render_template("register.html", form=form)
    
  • 模板文件中

    <form method="post">
        # 设置csrf_token
        {{ form.csrf_token() }}
    
        {{ form.user_name.label }}
        <p>{{form.user_name}}</p>
        {% for msg in form.user_name.errors %}  # 显示错误的提示信息
        <p>{{msg}}</p>
        {% endfor %}
    
        {{ form.pw.label }}
        <p>{{form.pw}}</p>
        {% for msg in form.pw.errors %}
        <p>{{msg}}</p>
        {% endfor %}
    
        {{ form.pw2.label }}
        <p>{{form.pw2}}</p>
        {% for msg in form.pw2.rrors %}
        <p>{{msg}}</p>
        {% endfor %}
    
        {{form.submit}}
     </form>
    
  • 要注意的是,因为有CSRF验证,所以还需配置SECRET_KEY参数

    app.config['SECRET_KEY'] = 'dasdasfdasx'
    
  • 表单校验时,如果form中的数据完全满足所有的验证器,则返回True,否则返回False

  • 类似于python中的函数,宏的作用就是在模板中重复利用代码,避免代码冗余

  • Jinja2支持宏,还可以导入宏,需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免重复

  • 不带参数的宏

    {% macro input() %}  # macro相当于def,后面为宏的名字
      <input type="text"
             name="username"
             value=""
             size="30"/>
    {% endmacro %}
    
    • 调用宏:{{ input() }}
  • 带参数的宏

    {% macro input(name,value='',type='text',size=20) %}
        <input type="{{ type }}"
               name="{{ name }}"
               value="{{ value }}"
               size="{{ size }}"/>
    {% endmacro %}
    
    • 调用:{{ input(value='name',type='password',size=40) }}
  • 把宏单独封装在HTML文件中

    • 如封装在macro.html文件中

      {% macro function() %}
          <input type="text" name="username" placeholde="Username">
          <input type="password" name="password" placeholde="Password">
          <input type="submit">
      {% endmacro %}
      
    • 在其他文件中,先导入再调用

      {% import 'macro.html' as func %}
      {% func.function() %}
      

模板继承

  • django的一样

    {% block xxx %}
    {% endlock %}
    

包含

  • 它的功能是将另一个模板整个加载到当前模板中,并直接渲染
    • {% include 'hello.html' %}
  • 如该模板文件不存在,则会抛出异常,加上 ignore missing时,则会忽略包含语句
    • {% include 'hello.html' ignore missing %}

数据库

  • SQLAlchemy是一个关系型数据库框架,flask-sqlalchemy则是一个简化版

  • 安装:

    pip install flask-sqlalchemy
    pip install flask-mysqldb
    
  • 配置使用Flask-SQLAlchemy来管理数据库

    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/test3'
    
  • 数据库的初始化配置

    class Config(object):
        """配置参数"""
        # sqlalchemy的配置参数
        SQLALCHEMY_DATABASE_URI = "mysql://root:mysql@127.0.0.1:3306/db_python04"
        # 设置sqlalchemy自动更跟踪数据库
        SQLALCHEMY_TRACK_MODIFICATIONS = True
    
    app.config.from_object(Config)
    
    # 创建数据库sqlalchemy工具对象
    db = SQLAlchemy(app)
    
    • 然后可以直接用db来操作数据库
  • 常用的SQLAlchemy字段类型

    类型名python中类型说明
    Integerint普通整数,一般是32位
    SmallIntegerint取值范围小的整数,一般是16位
    BigIntegerint或long不限制精度的整数
    Floatfloat浮点数
    Numericdecimal.Decimal普通整数,一般是32位
    Stringstr变长字符串
    Textstr变长字符串,对较长或不限长度的字符串做了优化
    Unicodeunicode变长Unicode字符串
    UnicodeTextunicode变长Unicode字符串,对较长或不限长度的字符串做了优化
    Booleanbool布尔值
    Datedatetime.date时间
    Timedatetime.datetime日期和时间
    LargeBinarystr二进制文件
  • 常用的SQLAlchemy列选项

    选项名说明
    primary_key如果为True,代表表的主键
    unique如果为True,代表这列不允许出现重复的值
    index如果为True,为这列创建索引,提高查询效率
    nullable如果为True,允许有空值,如果为False,不允许有空值
    default为这列定义默认值
  • 常用的SQLAlchemy关系选项

    选项名说明
    backref在关系的另一模型中添加反向引用
    primary join明确指定两个模型之间使用的联结条件
    uselist如果为False,不使用列表,而使用标量值
    order_by指定关系中记录的排序方式
    secondary指定多对多中记录的排序方式
    secondary join在SQLAlchemy中无法自行决定时,指定多对多关系中的二级联结条件

创建模型类

from flask import Flask
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)


class Config(object):
    """配置参数"""
    # sqlalchemy的配置参数
    SQLALCHEMY_DATABASE_URI = "mysql://root:mysql@127.0.0.1:3306/db_python04"
    # 设置sqlalchemy自动更跟踪数据库
    SQLALCHEMY_TRACK_MODIFICATIONS = True
app.config.from_object(Config)

# 创建数据库sqlalchemy工具对象
db = SQLAlchemy(app)

class Role(db.Model):
    """用户角色/身份表"""
    __tablename__ = "tbl_roles"  # 指明数据库的表名

    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32), unique=True)
    users = db.relationship("User", backref="role")

# 表名的常见规范:数据库名缩写_表名
# 创建数据库模型类
class User(db.Model):
    """用户表"""
    __tablename__ = "tbl_users"  

    id = db.Column(db.Integer, primary_key=True)  # 整型的主键,会默认设置为自增主键
    name = db.Column(db.String(64), unique=True)
    email = db.Column(db.String(128), unique=True)
    password = db.Column(db.String(128))
    role_id = db.Column(db.Integer, db.ForeignKey("tbl_roles.id"))  

id = db.Column(db.Integer, primary_key=True) Integer为字段类型,primary_key相当于约束;

users = db.relationship("User", backref="role") 相当于给Role添加了一个users属性,方便从Role查询User中的信息,backref="role"反向应用,相当于是给User添加了一个role属性,方便反过来查询

role_id为外键,db.ForeignKey("tbl_roles.id")指明与哪张表哪个字段关联

  • 自定义显示信息

    • 在模型类中

      def __repr__(self):
      	"""定义之后,可以让显示对象的时候更直观"""
      	return "Role object: name=%s" % self.name
      

创建数据库表

  • Flask开始没有像Django的终端命令创建数据库表,锝用到扩展才行,要创建数据库表,可以用

    # 清除数据库里的所有数据(第一次,里面可能会有垃圾数据,之后就慎用)
    db.drop_all()
    # 创建所有的表
    db.create_all()
    

数据操作

  • # 创建对象
    role1 = Role(name="admin")
    # session记录对象任务
    db.session.add(role1)
    # 提交任务到数据库中
    db.session.commit()
    
    role2 = Role(name="stuff")
    db.session.add(role2)
    db.session.commit()
    
    us1 = User(name='wang', email='wang@163.com', password='123456', role_id=role1.id)
    us2 = User(name='zhang', email='zhang@189.com', password='201512', role_id=role2.id)
    us3 = User(name='chen', email='chen@126.com', password='987654', role_id=role2.id)
    us4 = User(name='zhou', email='zhou@163.com', password='456789', role_id=role1.id)
    
    # 一次保存多条数据
    db.session.add_all([us1, us2, us3, us4])
    db.session.commit()
    
  • 查询

    Role.query.all()  # 查询所有,它返回的结果是Role的对象
    Role.query.first()  # 查询第一条
    Role.query.get(2)  #  根据主键id获取对象,若不存在,Django会报错,而Flask中则为None
    # 另一种查询方式
    db.session.query(Role).all()
    # 过滤器
    User.query.filter_by(name="fxh").all()
    User.query.filter_by(name="wang", role_id=2).first()
    User.query.filter(User.name=="wang", User.role_id==1).all()
    
    • 模糊查询:or_not_(相当与去反)

      from sqlalchemy import not_
      User.query.filter(not_(User.name=='chen')).all()
      
    • 降序

      User.query.order_by(User.id.desc()).all()
      
    • 关联查询

      role = Role.query.get(1)
      ro.users[0].name
      
      Role.query.get(user.role_id)
      
  • 更新

    • 查询后更改

      user.name = 'fxh'
      db.session.add(user)
      db.session.commit()
      
    • 查询时就更改

      User.query.filter_by(name='fxh').updata({'name':'python'})
      db.session.commit()
      
  • 删除

    user = User.query.get(2)
    db.session.delete(user)
    db.session.commit()
    

数据库迁移

  • 在开发过程中,需要修改数据库模型,而且还要在修改之后更新数据库。最直接的方式就是删除旧表,但这样会丢失数据,这时就需要用到数据库的迁移框架,它可以追踪数据库模式的变化,然后把变动应用到数据库中

  • 安装Flask-Migrate

    pip install flask-migrate
    
  • 使用(database.html)

    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from flask_migrate import Migrate,MigrateCommand
    from flask_script import Manager
    
    app = Flask(__name__)
    # 创建启动命令管理对象
    manager = Manager(app)
    
    app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://root:mysql@127.0.0.1:3306/Flask_test'
    # 设置sqlalchemy自动更跟踪数据库
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
    db = SQLAlchemy(app)
    
    # 创建数据库迁移工具对象
    Migrate(app,db) 
    
    # 向启动命令管理对象中添加迁移命令
    manager.add_command('db',MigrateCommand)
    
    #定义模型Role
    class Role(db.Model):
        pass
    
    #定义用户类
    class User(db.Model):
        pass
    
    if __name__ == '__main__':
        manager.run()
    

    Migrate(app,db) :第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例;

    manager.add_command('db',MigrateCommand)managerFlask-Script的实例,这条语句在flask-Script中添加一个名为db命令

  • 创建迁移仓库(终端)

    # 这个命令会创建migrations文件夹,所有迁移文件都放在里面。
    python database.py db init  # database.py为上面程序所在的文件
    
  • 创建迁移脚本

    #创建自动迁移脚本
    python database.py db migrate -m 'initial migration'
    

    该条语句会让迁移仓库中多一条迁移版本文件;等价与Django的*makemigations*

    -m后面的为备注信息,可不加

  • 更新数据库

    # 把迁移文件同步到数据库中
    python database.py db upgrade
    
  • 查看历史操作记录:python database.py db history

  • 回退数据库:python database.py db downgrade 版本号


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值