Flask之WTF和SQLAlchemy(4)

本文介绍了Flask中的两个重要扩展:Flask-WTF和Flask-SQLAlchemy。Flask-WTF简化了Web表单的创建和验证,而Flask-SQLAlchemy则是一个方便的ORM,让开发者能以Python对象操作数据库。文章提供了使用示例,包括表单定义、验证、数据库操作等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 Flask WTF

Web应用程序的一个重要方面是为用户提供用户界面。HTML提供了一个标签,用于设计界面。可以适当地使用Form(表单)元素,例如文本输入,单选按钮,选择等。
用户输入的数据以Http请求消息的形式通过GET或POST方法提交给服务器端脚本。

  • 服务器端脚本必须从http请求数据重新创建表单元素。因此,实际上,表单元素必须定义两次 一次在HTML中,另一次在服务器端脚本中。
  • 使用HTML表单的另一个缺点是很难(如果不是不可能的话)动态呈现表单元素。HTML本身无法验证用户的输入。

在Flask中,为了处理web表单,我们一般使用Flask-WTF扩展,它封装了WTForms,使用Flask-WTF表单扩展,可以帮助进行CSRF验证,帮助我们快速定义表单模板,而且可以帮助我们在视图中验证表的数据。使用Flask-WTF,我们可以在Python脚本中定义表单字段,并使用HTML模板进行渲染。还可以将验证应用于WTF字段。

三方包安装:

pip install flask-WTF

标准表单字段
WTforms包中包含各种表单字段的定义。下面列出了一些标准表单字段:

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

WTForms常用验证函数

验证函数说明
DataRequired确保字段中有数据
Email检查字段中的文本是否遵循电子邮件ID约定
IPAddress在输入字段中验证IP地址
EqualTo比较两个字段的值,常用于比较两次密码输入
Length验证输入的字符串长度
NumberRange验证输入的值在数字范围内
URL验证URL
AnyOf验证输入值在可选列表中
NoneOf验证输入值不在可选列表中

注意
使用Flask-WTF需要配置参数SECRET_KEY。
CSRF_ENABLED是为了CSRF(跨站请求伪造)保护。 SECRET_KEY用来生成加密令牌,当CSRF激活的时候,该设置会根据设置的密匙生成加密令牌。

用法示例:

from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField, RadioField, IntegerField, SelectField
from wtforms import validators, ValidationError
from flask import Flask, render_template, request, flash

app = Flask(__name__)
app.secret_key = 'development key'

#定义表单模型
class ContactForm(FlaskForm):
   # label: 名字    validators:验证器/验证器
   name = StringField(label="名字", validators=[validators.DataRequired("输入名字")])
   gender = RadioField(label='性别', choices=[('M', 'Male'), ('F', 'Female')])
   address = TextAreaField(label="地址")
   email = StringField(label="邮箱", validators=[validators.DataRequired("输入邮件地址"),
                               validators.Email("输入邮件地址,必须满足格式**@**")])
   age = IntegerField(label="年龄")
   language = SelectField(label='语言', choices=[('cpp', 'C++'),
                                                ('py', 'Python')])
   submit = SubmitField(label="提交")

@app.route("/contact", methods=["POST", "GET"])
def contact():
   form = ContactForm()
   if request.method == "POST":
      # 判断form中的数据是否合理
      # 如果form中的数据完全满足所有的验证器,则返回真,否则返回假
      if not form.validate_on_submit():
         name = form.name.data
         email = form.email.data
         gender = form.gender.data
         address = form.address.data
         print("数据错误")
         print(name, email, gender, address)
         flash('填入数据')
         return render_template('contact.html', form=form)
      else:
         name = form.name.data
         email = form.email.data
         print(name, email)
         return render_template("success.html")
   elif request.method == 'GET':
      return render_template('contact.html', form=form)


if __name__ == '__main__':
   app.run(debug=True)

contact.html内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
      {% for message in form.name.errors %}
         <div>{{ message }}</div>
      {% endfor %}

      {% for message in form.email.errors %}
         <div>{{ message }}</div>
      {% endfor %}
    <form action = "http://localhost:5000/contact" method="POST">
        <div style = font-size:20px; font-weight:bold; margin-left:150px;>
               {{ form.name.label }}<br>
               {{ form.name }}
               <br>
               {{ form.gender.label }}
                {{ form.gender }} <br>

               {{ form.address.label }}
               {{ form.address }}
               <br>

               {{ form.email.label }}<br>
               {{ form.email }}
               <br>

               {{ form.age.label }}<br>
               {{ form.age }}
               <br>

               {{ form.language.label }}<br>
               {{ form.language }}
               <br>
                {{ form.csrf_token }}
               {{ form.submit }}

        </div>
    </form>


</body>
</html>

success.html内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    Form posted success!!!
</body>
</html>

浏览器输入URL:http://localhost:5000/contact
在这里插入图片描述
点击提交
在这里插入图片描述

2 Flask SQLAlchemy

Flask本身不限定数据库的选择,你可以选择SQL或NOSQL的任何一种。也可以选择更方便的SQLALchemy,类似于Django的ORM。SQLALchemy实际上是对数据库的抽象,让开发者不用直接和SQL语句打交道,而是通过Python对象来操作数据库,在舍弃一些性能开销的同时,换来的是开发效率的较大提升。
SQLAlchemy是一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作。flask-sqlalchemy是一个简化了SQLAlchemy操作的flask扩展。
常用的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查询过滤器

过滤器说明
filter()把过滤器添加到原查询上,返回一个新查询
filter_by()把等值过滤器添加到原查询上,返回一个新查询
limit使用指定的值限定原查询返回的结果
offset()偏移原查询返回的结果,返回一个新查询
order_by()根据指定条件对原查询结果进行排序,返回一个新查询
group_by()根据指定条件对原查询结果进行分组,返回一个新查询

常用的SQLAlchemy查询执行器

方法说明
all()以列表形式返回查询的所有结果
first()返回查询的第一个结果,如果未查到,返回None
first_or_404()返回查询的第一个结果,如果未查到,返回404
get()返回指定主键对应的行,如不存在,返回None
get_or_404()返回指定主键对应的行,如不存在,返回404
count()返回查询结果的数量
paginate()返回一个Paginate对象,它包含指定范围内的结果

SQLAlchemy常用操作
SQLAlchemy的Session对象管理ORM对象的所有持久性操作。
以下session方法执行CRUD操作:
db.session.add (模型对象) - 将记录插入到映射表中
db.session.delete (模型对象) - 从表中删除记录
model.query.all() - 从表中检索所有记录(对应于SELECT查询)
可以通过使用filter属性将过滤器应用于检索到的记录集。例如,要在学生表中检索city ='Hyderabad’的记录:

Students.query.filter_by(city = ’Hyderabad’).all()

程序代码示例:

from flask import Flask, render_template, request, flash, redirect, url_for

from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.secret_key = 'development key'

class Config(object):
   # sqlalchemy的配置参数 帐号:密码@地址:端口/数据库
   SQLALCHEMY_DATABASE_URI = "mysql+pymysql://root:127.0.0.1:3306/test_db"
   # 设置sqlalchemy自动更跟踪数据库(数据库表手动更新是同步跟新到对象)
   SQLALCHEMY_TRACK_MODIFICATIONS = True

   #查询时会显示原始SQL语句
   SQLALCHEMY_ECHO = True

#加载数据库配置对象
app.config.from_object(Config)
# 创建数据库sqlalchemy工具对象
db = SQLAlchemy(app)

class students(db.Model):

   id = db.Column('student_id', db.Integer, primary_key=True)
   name = db.Column(db.String(100))
   city = db.Column(db.String(50))
   addr = db.Column(db.String(200))
   pin = db.Column(db.String(10))

   def __init__(self, name, city, addr, pin):
      self.name = name
      self.city = city
      self.addr = addr
      self.pin = pin

@app.route('/')
def show_all():
   return render_template('show_all.html', students=students.query.all())

@app.route('/new', methods=['GET', 'POST'])
def new():
   if request.method == 'POST':
      if not request.form['name'] or not request.form['city'] or not request.form['addr']:
         flash('Please enter all the fields', 'error')
      else:
         student = students(request.form['name'], request.form['city'],
                            request.form['addr'], request.form['pin'])

         db.session.add(student)
         db.session.commit()
         flash('Record was successfully added')
         return redirect(url_for('show_all'))
   return render_template('new.html')

if __name__ == '__main__':
   db.create_all()
   app.run(debug=True)

new.html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
    <form action="{{ request.path }}" method="post">
        <label for="name">Name</label><br>
        <input type = "text" name = "name" placeholder = "Name" /><br>
        <label for = "city">City</label><br>
        <input type = "text" name = "city" placeholder = "city" /><br>
        <label for = "addr">addr</label><br>
        <textarea name = "addr" placeholder = "addr"></textarea><br>
        <label for = "PIN">pin</label><br>
         <input type = "text" name = "pin" placeholder = "pin" /><br>
         <input type = "submit" value = "Submit" />

    </form>

</body>
</html>

show_all.html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
</head>
<body>
      <h3>
         <a href = "{{ url_for('show_all') }}">Comments - Flask
            SQLAlchemy example</a>
      </h3>
    <hr/>
      {%- for message in get_flashed_messages() %}
         {{ message }}
      {%- endfor %}

      <h3>Students (<a href = "{{ url_for('new') }}">Add Student
         </a>)
      </h3>

    <table>
        <thead>
        <tr>
            <th>Name</th>
            <th>City</th>
            <th>Address</th>
            <th>Pin</th>
        </tr>
        </thead>
         <tbody>
            {% for student in students %}
               <tr>
                  <td>{{ student.name }}</td>
                  <td>{{ student.city }}</td>
                  <td>{{ student.addr }}</td>
                  <td>{{ student.pin }}</td>
               </tr>
            {% endfor %}
         </tbody>
    </table>

</body>
</html>

参考文献:
https://www.jianshu.com/p/3fd2a1f155f3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值