Flask学习记录

Flask是一个使用Python编写的轻量级web框架,相比其他框架如Django更加简单易学。本文将实现一个简单示例,完成以下功能:从数据库中读取用户信息,在浏览器中分页展示,添加分页导航栏,并且实现根据用户名搜索。用到的主要知识点:数据库操作、表单、Jinja2模板。

学习环境搭建

操作系统

CentOS Linux release 7.4.1708 (Core)

执行yum update -y然后重启系统,确保软件包处于最新状态。

Python版本 2.7.5

安装Python虚拟环境

利用virtualenv可以实现一个隔离的Python环境,在这个虚拟环境中安装、删除Python的pip包而不会影响环境外的其他进程。虚拟环境还会让系统移植更容易,只要把虚拟环境的文件拷到另一个系统中然后恢复虚拟环境,就可以保证跟之前的Python包环境一模一样。

安装virtualenv:

[[email protected] ~]# pip install virtualenv

Collecting virtualenv

Downloading virtualenv-15.1.0-py2.py3-none-any.whl (1.8MB)

100% |████████████████████████████████| 1.8MB 78kB/s

Installing collected packages: virtualenv

Successfully installed virtualenv-15.1.0

创建一个名为env的虚拟环境:

[[email protected] ~]# virtualenv env

New python executable in /root/env/bin/python2

Also creating executable in /root/env/bin/python

Installing setuptools, pip, wheel...done.

进入虚拟环境env:

[[email protected] demo]# source env/bin/activate

(env) [[email protected] demo]#

前面的(env)标识了当前shell所在的虚拟环境,把env目录拷到其他系统就可以进行环境移植。

安装数据库

安装数据和相关开发包:

[[email protected] demo]# yum install mariadb mariadb-server python-devel mariadb-devel -y

安装完后,执行mysql_secure_installation,设置数据库root密码,因为是测试环境,我们为了方便设置为“test”,生产环境的话一定要设置复杂密码。

简单示例实现

项目结构

我们创建一个demo目录存放项目文件,用tree命令查看这个目录的结构如下:

(env) [[email protected] ~]# tree -I 'env' demo

demo

├── app                #程序包目录

│   ├── __init__.py

│   ├── main

│   │   ├── forms.py    #定义表单类

│   │   ├── __init__.py

│   │   ├── views.py    #定义视图函数,实际处理http请求

│   ├── models.py      #定义数据模型

│   ├── static           #存放静态文件

│   └── templates       #存放模板

│       ├── _macro.html

│       ├── userlist.html

├── config.py           #项目配置文件

├── manage.py         #项目启动脚本

└── requirements.txt     #项目依赖的所有pip包

各文件的主要作用已经在上面注释。Flask并没有限定项目的结构必须如此,但是通常这是比较合理的结构,也可以根据自己的项目特点进行微调。下面分文件详细介绍如何实现本文开头提到的各个功能。

requirements.txt

这个文件保存了项目依赖的所有包及其版本,方便其他人移植你的Flask项目。文件是由命令pip freeze > requirements.txt生成的,在要运行该项目的系统中执行pip install -r requirements.txt就可以安装完所有依赖包,很方便。这个示例的requirements.txt内容如下:

alembic==0.9.6

click==6.7

Flask==0.12.2

Flask-Migrate==2.1.1

Flask-Script==2.0.6

Flask-SQLAlchemy==2.3.2

Flask-WTF==0.14.2

ForgeryPy==0.1

itsdangerous==0.24

Jinja2==2.10

Mako==1.0.7

MarkupSafe==1.0

MySQL-python==1.2.5

python-dateutil==2.6.1

python-editor==1.0.3

six==1.11.0

SQLAlchemy==1.2.0

Werkzeug==0.14.1

WTForms==2.1

config.py

项目的配置文件,集中存放配置参数,内容如下:

class Config:

SQLALCHEMY_DATABASE_URI = "mysql://root:[email protected]/demo"

SQLALCHEMY_COMMIT_ON_TEARDOWN = True

SECRET_KEY = 'hard to guess string'

@staticmethod

def init_app(app):

pass

文件中配置了数据库的访问方式,还有SECRET_KEY,这是一个密钥,用于保护表单免受跨站请求伪造(CSRF)的攻击。

models.py

编写业务逻辑前要先设计好数据模型,我们的示例的数据很简单,一张表——用户信息,包括两个字段:用户名和用户邮箱地址。代码如下:

from . import db

class User(db.Model):

__tablename__ = 'users'

id = db.Column(db.Integer, primary_key=True)

username = db.Column(db.String(64), unique=True, index=True)

email = db.Column(db.String(64), unique=True, index=True)

def __repr__(self):

return '<User %r>' % self.username

@staticmethod

def generate_fake(count=100):

from sqlalchemy.exc import IntegrityError

from random import seed

import forgery_py

seed()

for i in range(count):

u = User(username=forgery_py.internet.user_name(True),

email=forgery_py.internet.email_address())

db.session.add(u)

try:

db.session.commit()

except IntegrityError:

db.session.rollback()

Flask-SQLalchemy是Flask的数据库扩展,通过对象关系映射ORM,把对数据库的操作转换为对Python对象的操作。Class User在数据库中对应的就是一张表,表名在__tablename__中设置,两个属性username和email对应表字段。代码中还用到了一个很有意思的模块forgery_py,它用于随机生成符合要求的测试数据,函数generate_fake()随机生成数量等于count条的数据并写入数据库。生成数据的具体操作方法会在最后执行程序的时候讲。

app/__init__.py

程序包的构建文件,在这文件里定义创建程序实例的函数create_app,也叫工厂函数。工厂函数完成3个主要工作:

1.      从config.py中导入程序配置;

2.      大多数Flask的扩展需要在这个函数里初始化,例如我们的示例用到的Flask数据库扩展Flask-Sqlalchemy;

3.      还有一个工作是给程序实例注册蓝本(blueprint),蓝本用于定义URL到视图函数的路由。

代码如下:

from flask import Flask

from flask_sqlalchemy import SQLAlchemy

from config import Config

db = SQLAlchemy()

def create_app(config_name):

app = Flask(__name__)

app.config.from_object(Config)

Config.init_app(app)

db.init_app(app)

from .main import main as main_blueprint

app.register_blueprint(main_blueprint)

return app

manage.py

manage.py是整个程序的启动脚本,从上面的app/__init__.py导入工厂函数create_app(),然后创建程序实例,初始化Flask的扩展Flask-Script和Flask-Migrate,代码如下:

#!/usr/bin/env python

#conding: utf-8

import os

from flask.ext.script import Manager, Shell

from flask.ext.migrate import Migrate, MigrateCommand

from app import create_app, db

from app.models import *

app = create_app('default')

manager = Manager(app)

migrate = Migrate(app, db)

def make_shell_context():

return dict(app=app, db=db, User=User)

manager.add_command("shell", Shell(make_context=make_shell_context))

manager.add_command('db', MigrateCommand)

if __name__ == '__main__':

manager.run()

forms.py

表单的功能是接收用户提供的数据。用户将数据填到表单的各字段中,通过Post方法提交给服务端。在我们的示例中,表单用于接收用户输入的用户名,用于后续的搜索功能。代码如下:

from flask_wtf import FlaskForm

from wtforms import StringField, SubmitField

from wtforms.validators import DataRequired

class Form(FlaskForm):

name = StringField('Username', validators=[DataRequired()])

submit = SubmitField('Search')

flask.wtf是Flask框架处理表单的扩展,我们自己定义的表单Form继承该模块中的FlaskForm类。Form很简单,一共2个字段,StringField提供给用户填写要搜索的用户名,检测函数DataRequired()确保数据不为空;SubmitField是一个提交按钮,用户点击按钮后,就会把表单数据提交给服务端。

views.py

该文件中定义路由和视图函数,视图函数是实际处理http请求的函数。我们的示例只有一个视图函数,代码如下:

from flask import render_template, url_for, request, session

from . import main

from .. import db

from ..models import User

from .forms import Form

@main.route('/',methods=['GET','POST'])

def index():

page = request.args.get('page',1,type=int)

pagination = User.query.order_by(User.id).paginate(

page,per_page=10,error_out=False)

form = Form()

users = pagination.items

if form.validate_on_submit():

session['username'] = form.name.data

users = User.query.filter_by(username=session.get('username')).all()

return render_template('userlist.html',users=users,pagination=pagination,form=form)

main是一个蓝本,修饰器@main.route定义的路由的含义是,访问“/”的的GET或POST方法都由index()函数处理。开头提到了我们要实现用户信息的分页展示,所以index()先从全局变量request中获取了页数,默认显示第1页。

然后分页查询数据库,每页10个数据;

然后初始化搜索表单,If判断把视图函数的执行结果分成了表单有数据和没数据两种情况:如果表单有数据,则把表单数据存到会话session中,并且查询数据库,把符合条件的用户传递给模板;如果表单没有数据,就把所有用户传递给模板。模板根据收到的用户信息生成html页面。

视图函数最核心的任务就是返回一个html页面给客户端,render_template()通过渲染模板生成一个html页面,所谓渲染就是根据传入的参数去修改模板中对应的可变部分。模板将在下一部分详细介绍。

templates

Flask集成了Jinja2模板引擎,templates这个目录存放所有jinja2模板。模板中有一些可以被替换的部分,渲染流程也支持通过条件判断或循环控制。

_macro.html中定义了一个宏pagination_widget,宏类似于Python中的函数,这个宏用于生成分页导航栏,它接收的参数是数据库分页查找返回的对象pagination和视图函数名endpoint。pagination对象支持一系列方法和属性:

l  方法has_prev()和has_next()分别检测当前页之前和之后还有没有页,返回布尔值;

l  方法prev()和next()分别返回上一页和下一页的分页对象

l  属性page返回当前页码;

l  方法iter_pages是一个迭代器,根据参数返回一组页码;

_macro.html代码如下:

{% macro pagination_widget(pagination, endpoint) %}

<style>

li{ list-style:none;}

</style>

<ul class="pagination">

    <tr>

    <td{% if not pagination.has_prev %} class="disabled"{% endif %}>

        <a href="{% if pagination.has_prev %}{{ url_for(endpoint, page=pagination.prev_num, **kwargs) }}{% else %}#{% endif %}">

            &laquo;

        </a>

    </td>

    {% for p in pagination.iter_pages(right_current=2) %}

        {% if p %}

            {% if p == pagination.page %}

            <td class="active">

                <a href="{{ url_for(endpoint, page = p, **kwargs) }}">{{ p }}</a>

            </td>

            {% else %}

            <td>

                <a href="{{ url_for(endpoint, page = p, **kwargs) }}">{{ p }}</a>

            </td>

            {% endif %}

        {% else %}

        <td class="disabled"><a href="#">&hellip;</a></td>

        {% endif %}

    {% endfor %}

    <td{% if not pagination.has_next %} class="disabled"{% endif %}>

        <a href="{% if pagination.has_next %}{{ url_for(endpoint, page=pagination.next_num, **kwargs) }}{% else %}#{% endif %}">

            &raquo;

        </a>

    </td>

    </tr>

</ul>

{% endmacro %}

其核心内容是中间的for循环,根据iter_pages()方法返回的页码,生成指向该页码的URL的链接。因此分页导航栏本质是由若干链接组成的,只不过这些特殊链接都指向与自己名字相关的URL。执行效果会在本文最后一部分看到。

userlist.html是视图函数index()真正渲染的文件,它通过一个列表来展示视图函数传给它的参数users中包含的用户信息。然后它引用了上面定义的宏,生成了分页导航栏。在最后是搜索表单。

{% import "_macro.html" as macro %}

<html>

<style>

li{ list-style:none;}

</style>

<body>

<h4>用户列表:</h4>

<ul>

{% for user in users%}

<li>{{ user.username }}: {{ user.email }}</li>

{% endfor %}

</ul>

<div>

    {{ macro.pagination_widget(pagination, '.index')}}

</div>

<form method="POST">

    {{ form.hidden_tag() }}

    {{ form.name.label }} {{ form.name() }}

    {{ form.submit() }}

</form>

</body>

</html>

执行效果

生成测试数据

(env) [root@localhost demo]# python manage.py shell

manage.py:6: ExtDeprecationWarning: Importing flask.ext.script is deprecated, use flask_script instead.

from flask.ext.script import Manager, Shell

manage.py:7: ExtDeprecationWarning: Importing flask.ext.migrate is deprecated, use flask_migrate instead.

from flask.ext.migrate import Migrate, MigrateCommand

/root/demo/env/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:794: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True or False to suppress this warning.

'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and '

>>> db.create_all()

>>> User.generate_fake(100)

db.create_all()创建所有表,User.generate_fake(100)生成表中的数据。

启动程序

Flask框架内置了一个用于测试的web服务器,启动服务:

(env) [root@localhost demo]# python manage.py runserver -h 0.0.0.0 -p 5000

manage.py:6: ExtDeprecationWarning: Importing flask.ext.script is deprecated, use flask_script instead.

from flask.ext.script import Manager, Shell

manage.py:7: ExtDeprecationWarning: Importing flask.ext.migrate is deprecated, use flask_migrate instead.

from flask.ext.migrate import Migrate, MigrateCommand

/root/demo/env/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:794: FSADeprecationWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True or False to suppress this warning.

'SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and '

* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)

访问页面

打开一个浏览器,输入URL http://x.x.x.x:5000/,x.x.x.x替换为你的测试机的ip,可以看到以下页面:

数据库中一共存了100条用户记录,分为了10页展示,点击下面的分页导航可以跳转页面,下面是第9页的内容:

然后测试搜索功能,在表单中输入“amy63”,点击按钮,结果如下:

原文地址:http://blog.51cto.com/3646344/2120170

时间: 2024-10-09 04:09:01

Flask学习记录的相关文章

[ZHUAN]Flask学习记录之Flask-SQLAlchemy

From: http://www.cnblogs.com/agmcs/p/4445583.html Flask-SQLAlchemy库让flask更方便的使用SQLALchemy,是一个强大的关系形数据库框架,既可以使用orm方式操作数据库,也可以使用原始的SQL命令. Flask-Migrate 是一个数据迁移框架,需要通过Flask-script库来操作. 一.配置Flask-SQLAlchemy 程序使用的数据库地址需要配置在SQLALCHEMY_DATABASE_URI中,SQLALch

Flask学习记录之MarkDown编辑文本

为了让网页支持markdown编辑文本,使用如下了4个库 PageDown : 在前端提供一个可以实时将markdown内容转换成html文本进行效果预览的编辑器 Flask-PageDown: 这个库将PageDown集成到Flask-Wtf库中,更方便使用 MarkDown: 将MarkDown标记文本转换为Html文本 Bleach: 基于白名单清除Html文本中不安全的标签 PageDown的使用 和其他类库相识,需要初始化 from flask.ext.pagedown import

Flask学习记录之Flask-Admin

相信用过Django框架的都不会忘记它强大的Admin功能,Flask-admin是一款能够与Django Admin所媲美的扩展,能够快速创建Web管理界面,实现了用户.文件增删改查等常用功能:也可以通过修改模板文件来定制管理页面. 初始化: from flask import Flask from flask_admin import Admin app = Flask(__name__) admin = Admin(app) # Add administrative views here

Flask学习记录之Flask-Mail

Flask-Mail可以连接到配置中的SMTP服务器,进行邮件发送,如果没有进行SMTP服务器的配置,将会默认连接到localhost上的 一.配置及初始化 (1)flask应用配置 #配置选项 MAIL_SERVER = 'smtp.qq.com' #邮件服务器 MAIL_PORT = 25 #端口 MAIL_USE_TLS = False#传输层安全协议 MAIL_USE_SSL = False #安全套接层协议 MAIL_USERNAME = 'you' #账号 MAIL_PASSWORD

Flask学习记录之Flask-SQLAlchemy,Flask-Migrate

Flask-SQLAlchemy库让flask更方便的使用SQLALchemy,是一个强大的关系形数据库框架,既可以使用orm方式操作数据库,也可以使用原始的SQL命令. Flask-Migrate 是一个数据迁移框架,需要通过Flask-script库来操作. 一.配置Flask-SQLAlchemy 程序使用的数据库地址需要配置在SQLALCHEMY_DATABASE_URI中,SQLALchemy支持多种数据库,配置格式如下: Postgres: postgresql://scott:[e

Flask学习记录之Flask-Moment

Moment.js 是一个简单易用的轻量级JavaScript日期处理类库,提供了日期格式化.日期解析等功能.它支持在浏览器和NodeJS两种环境中运行.此类库能够 将给定的任意日期转换成多种不同的格式,具有强大的日期计算功能,同时也内置了能显示多样的日期形式的函数.另外,它也支持多种语言,你可以任意新增一种 新的语言包. Flask-Moment是一个集成moment.js到Jinja2模板的Flask扩展. 一.初始化Flask-Moment from flask.ext.moment im

Flask学习记录之Flask-Migrate

一.配置Flask-Migrate from flask.ext.migrate import Migrate, MigrateCommand migrate = Migrate(app,db) #第一个参数是Flask的实例,第二个参数是Sqlalchemy数据库实例 manager.add_command('db', MigrateCommand) #manaer 是Flask-Script的实例,这条语句在flask-script 中添加一个db命令 二.使用Flask-Migrate 在

Flask学习记录之使用Werkzeug散列密码

数据库中直接存放明文密码是很危险的,Werkzeug库中的security能够方便的实现散列密码的计算 security库中 generate_password_hash(password,method...)函数将原始密码作为输入,以字符串形式输出密码的散列值 check_password_hash(hash,password)函数检查给出的hash密码与明文密码是否相符 应用在用户模型中 from werkzeug.security import check_password_hash,ge

HTML学习记录(一)

HTML学习记录 起因是买了本书学习flask,书里让我自己学HTML--超文本标记语言即HTML,HTML文档以.html为后缀.HTML是一种用来描述网页的标记语言,是一套标记标签,因此HTML使用标记标签来描述网页.HTML标签有以下特征: ·标签是由尖括号<>包围的关键字 ·标签通常是成对出现的,如<p>和</p> ·一对标签中第一个是开始标签,第二个是结束标签 ·格式为内容 1.<!DOCTYPE html> HTML文档第一行必须是<!DO