overview
in WebapplicationDevelopmentin, 表单processing and datalibrary交互 is corefunctions. Flaskproviding了flexible scaleecosystem, 让我们可以easilyimplementation这些functions. 本章节将介绍such as何usingWTFormsprocessing表单, 以及such as何usingSQLAlchemyfordatalibraryoperation.
1. Flask-WTF表单processing
Flask-WTF is Flask 一个scale, 它集成了WTFormslibrary, providing了表单verification, CSRF保护etc.functions.
1.1 installationFlask-WTF
pip install flask-wtf
1.2 creation表单class
我们可以throughcreation一个inheritance自FlaskForm class来定义表单:
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField, TextAreaField
from wtforms.validators import DataRequired, Length, Email, EqualTo
class RegistrationForm(FlaskForm):
username = StringField('user名', validators=[DataRequired(), Length(min=2, max=20)])
email = StringField('邮箱', validators=[DataRequired(), Email()])
password = PasswordField('password', validators=[DataRequired()])
confirm_password = PasswordField('确认password', validators=[DataRequired(), EqualTo('password')])
submit = SubmitField('register')
class LoginForm(FlaskForm):
email = StringField('邮箱', validators=[DataRequired(), Email()])
password = PasswordField('password', validators=[DataRequired()])
submit = SubmitField('login')
1.3 in 视graphinprocessing表单
in 视graphfunctionin, 我们可以instance化表单object并processing表单submitting:
from flask import render_template, flash, redirect, url_for
from app import app
from app.forms import RegistrationForm, LoginForm
@app.route("/register", methods=['GET', 'POST'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
flash(f'账号creation成功!欢迎 {form.username.data}', 'success')
return redirect(url_for('home'))
return render_template('register.html', title='register', form=form)
@app.route("/login", methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
# 这里应该添加practical userverification逻辑
if form.email.data == 'admin@example.com' and form.password.data == 'password':
flash('login成功!', 'success')
return redirect(url_for('home'))
else:
flash('login失败, 请check邮箱 and password', 'danger')
return render_template('login.html', title='login', form=form)
1.4 in 模板in渲染表单
in HTML模板in, 我们可以usingFlask-WTFproviding 辅助function来渲染表单:
<form method="POST" action="">
{{ form.hidden_tag() }}
<fieldset class="form-group">
<legend class="border-bottom mb-4">register</legend>
<div class="form-group">
{{ form.username.label(class="form-control-label") }}
{% if form.username.errors %}
{{ form.username(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.username.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.username(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.email.label(class="form-control-label") }}
{% if form.email.errors %}
{{ form.email(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.email.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.email(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.password.label(class="form-control-label") }}
{% if form.password.errors %}
{{ form.password(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.password.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.password(class="form-control form-control-lg") }}
{% endif %}
</div>
<div class="form-group">
{{ form.confirm_password.label(class="form-control-label") }}
{% if form.confirm_password.errors %}
{{ form.confirm_password(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in form.confirm_password.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ form.confirm_password(class="form-control form-control-lg") }}
{% endif %}
</div>
</fieldset>
<div class="form-group mt-4">
{{ form.submit(class="btn btn-primary btn-lg") }}
</div>
</form>
2. Flask-SQLAlchemydatalibraryoperation
SQLAlchemy is Pythonin最流行 ORM (objectrelationshipsmap) library之一. Flask-SQLAlchemy is Flask 一个scale, 它简化了SQLAlchemy in Flaskapplicationin using.
2.1 installationFlask-SQLAlchemy
pip install flask-sqlalchemy
2.2 configurationdatalibrary
in Flaskapplicationin, 我们需要configurationdatalibraryURI:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db' # SQLitedatalibrary
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
2.3 creationdatalibrarymodel
我们可以throughcreation一个inheritance自db.Model class来定义datalibrarymodel:
from datetime import datetime
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
def __repr__(self):
return f"<User {self.username}>"
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"<Post {self.title}>"
2.4 creationdatalibrary
in Flask shellin, 我们可以creationdatalibrary and 表:
>>> from app import db
>>> db.create_all()
2.5 datalibraryoperation
我们可以usingSQLAlchemyproviding API来执行datalibraryoperation:
添加data
from app import db, User, Post
# creationuser
user = User(username='john', email='john@example.com', password='password')
db.session.add(user)
db.session.submitting()
# creation文章
post = Post(title='First Post', content='Hello World!', author=user)
db.session.add(post)
db.session.submitting()
querydata
# query所 has user
users = User.query.all()
# query单个user
user = User.query.filter_by(username='john').first()
# queryuser 所 has 文章
posts = user.posts
# query所 has 文章
posts = Post.query.all()
updatedata
user = User.query.filter_by(username='john').first()
user.username = 'john_doe'
db.session.submitting()
deletedata
user = User.query.filter_by(username='john_doe').first()
db.session.delete(user)
db.session.submitting()
3. datalibrarymigration
in Development过程in, 我们经常需要modifydatalibrarymodel. Flask-Migrate is a scale, 它providing了datalibrarymigrationfunctions, 让我们可以security地updatedatalibrarystructure.
3.1 installationFlask-Migrate
pip install flask-migrate
3.2 初始化migration
in applicationinconfigurationFlask-Migrate:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
.db = SQLAlchemy(app)
migrate = Migrate(app, db)
3.3 creationmigration仓library
flask db init
3.4 creationmigration脚本
flask db migrate -m "Initial migration"
3.5 applicationmigration
flask db upgrade
3.6 rollbackmigration
flask db downgrade
4. 综合example: 博客application
让我们creation一个 simple 博客application, 综合运用表单processing and datalibraryoperation:
4.1 projectstructure
blog_app/
├── app/
│ ├── __init__.py
│ ├── forms.py
│ ├── models.py
│ ├── routes.py
│ ├── static/
│ └── templates/
│ ├── base.html
│ ├── home.html
│ ├── login.html
│ ├── register.html
│ └── post.html
└── run.py
4.2 implementation要点
- usingFlask-WTFcreationregister, login and 文章表单
- usingSQLAlchemy定义User and Postmodel
- implementationuserregister, loginfunctions
- implementation文章 creation, 查看functions
- using模板inheritance保持页面风格一致
4.3 runapplication
flask run
5. best practices
- 始终usingFlask-WTF
form.hidden_tag()来package含CSRFtoken - for userpasswordfor哈希processing, 不要store明文password (可以usingFlask-Bcrypt)
- usingdatalibrarymigration来managementdatalibrarystructure变更
- in produceenvironmentinusing强password and security datalibraryconfiguration
- usingSQLAlchemy queryoptimizationfunctions, such as
lazy='dynamic'来processing big 量data
summarized
本章节介绍了Flaskin 表单processing and datalibraryoperation, including:
- usingFlask-WTFcreation and verification表单
- usingFlask-SQLAlchemyfordatalibraryoperation
- usingFlask-Migratefordatalibrarymigration
- 综合example: 博客application
这些functions is 构建现代Webapplication Basics, Master它们将helping你Development出functions完整, security reliable Flaskapplication.