web开发之flask简介


flask是一个很简易的web框架,接下来我们将一步步建立一个完整的网站服务。
使用如下代码安装flask

pip install flask

启动服务的方法:

export FLASK_APP=schedule.py
export FLASK_DEBUG=True
flask run --debugger --host=0.0.0.0

上面的代码是可调试的,如果要正式发布,则应该将debug相关内容删除。
最后的–host部分使得服务可以远程访问。

1. 基本概念

1.1 初始化

构造函数的__name__变量决定程序的根目录。

from flask import Flask
app = Flask(__name__)

1.2 路由和视图函数

客户端的URL需要转换为服务器的python函数,其映射关系称为路由,使用app.route修饰器可以将函数进行注册,被注册的函数称为视图函数。
此外,也可以使用app.add_url_rule()生成映射。
视图函数可以带参数,默认为string类型,也可以指定为int,float,path类型,使用<int: id>的方式。参考下面的例子:

@app.route('/')
def index()
	return '<h1>Hello World!</h1>'

@app.route('/user/<name>')
def user(name):
	return '<h1>Hello, %s</h1>' % name

1.3 上下文

Flask使用上下文访问客户端返回的http请求对象。上下文分为以下四种:

变量 上下文 说明
current_app 程序 激活程序的实例
g 程序 处理请求时用作临时存储的对象
request 请求 请求对象,封装了客户端发出的额HTTP请求中的内容
session 请求 用户会话,存储需要记住的值的词典。session在关闭浏览器之后失效

无论是哪一个,在使用之前都要先引入:

from flask import request,session

session的定义很简单,下面是例子,注意使用get()方法比较安全,对于不存在的键,返回默认值None。

session['user'] = form.username.data
...
name = session.get('user')

request有post和get两种方式,下面是例子:
模板代码:

$.ajax({
    type:'POST',
    url:"/saveAction",
    contentType:'application/json; charset=UTF-8',
    data:JSON.stringify({'clng':lng,'clat':lat}),
    dataType:'json'
})
        
$.get('/getGeo',{lat:clat,lng:clng},function(data){
    var d = data;
})

后台python代码:

import mzgeohash as geo
@app.route('/getGeo')
def getGeo():
    lat = float(request.args.get('lat'))
    lng = float(request.args.get('lng'))
    return  geo.encode((lng,lat))[:7]

@app.route('/saveAction', methods=['POST'])
def saveAction():
    d = json.loads(request.get_data())
    lat =  float(d['lat'])
    lng =  float(d['lng'])
    session['lat'] = lat
    session['lng'] = lng
    return 'success'

1.4 响应和重定向

可以使用make_response方法封装响应,可以接受作为html页面返回的字符串、装填吗和header字典。使用make_response还有一个好处是可以设置cookie:

resp = make_response("set cookie OK")
resp.set_cookie("settime","python2",max_age=3600)

使用redirect可以执行重定向的响应,如下:

from flask import redirect,url_for
@app.route('/')
def index():
	return redirect(url_for('login'))

其中url_for接收视图函数名,返回对应的url。

1.5 Flash消息传递

Flash是只显示一次的数据。使用前需要import。
使用方法很简单,下面是例子:

flash('you changed your name')

然后在模板中使用get_flashed_messages方法获得消息。使用for循环是因为消息有可能会排队。

{% for message in get_flashed_messages() %}
	{{message}}
{% endfor %}

2. 模板

模板指的是包含相应文本的文件,包含用占位变量表示的动态部分。Flask把静态文件放置在根目录下的static文件夹下。注意要使用中文的话,需要在python代码最前面加上:

#coding=utf-8

然后在所有中文字符串前面加上u。

2.1 渲染过程

使用真实值替换变量,再返回最终相应字符串的过程称为渲染
Flask使用Jinja2引擎,代码中使用render_template渲染模板。渲染时可以传递参数,参考如下代码:

from flask import render_template
...
@app.route('/user/<name>')
def user(name):
	return render_template('user.html',name = 'ie06')

这样,模板中的name就会被替换为’ie06’。默认情况下,Flask在templates文件夹中寻找模板,变量用两个中括号表示,示例如下:

<h1>Hello, {{name}}</h1>

可以为变量添加管道函数,例如
{{name|capitalize}},则name会变成’Ie06’

2.2 控制结构

使用{% %}添加控制结构。例如:

{% if user%}
    Hello, {{user}}!
{% else %}
    Hello, Stranger!
{% endif %}   
<ul>
	{% for comment in comments %}
		<li>{{comment}}</li>
	{% endfor %}
</ul>

另外有一个模板继承的重要功能,首先定义个基础模板base.html,中间添加

{% block body %}{% endblock %}

然后在衍生文件中使用

{% extends "base.html" %}
{% block body %}...{% endblock %}

就可以将base.html中的内容加载到衍生文件中了。

2.3 bootstrap

bootstrap是Twitter开发的一个开源框架,python下需要安装,是一套非常好用的模板。

pip install flask-bootstrap

使用如下方法引入bootstrap模板:

from flask_bootstrap import Bootstrap
...
bootstrap = Bootstrap(app)

然后在模板中使用:

{% extends "bootstrap/base.html" %}

这里有不少示例可供参考。

3. 表单

使用Flask-WTF创建表单。使用之前先用pip进行安装。

3.1 启用CSRF保护

设置一个密钥,然后程序使用密钥生成加密令牌,用于验证表单中数据的真伪:

class Config(object):
    SECRET_KEY = 'a9087FFJFF9nnvc2@#$%FSD'
app = Flask(__name__)
app.config.from_object(Config)

3.2 创建表单类

每个表单由一个表单类来表示,各种filed使用.data取出对应的值。
第一次访问程序时,服务器接收到的是没有数据的GET请求,validate_on_submit返回False。填写好内容并提交表单后,服务器收到包含数据的POST请求,validate_on_submit返回True。
参考下面的代码:

from flask_wtf import FlaskForm
from wtforms import StringField,PasswordField,BooleanField,SubmitField
from wtforms.validators import DataRequired
class LoginForm(FlaskForm):
    #DataRequired,当你在当前表格没有输入而直接到下一个表格时会提示你输入
    username = StringField(unicode('用户', encoding='utf-8'),validators=[DataRequired(message='input username')])
    password = PasswordField(unicode('密码', encoding='utf-8'),validators=[DataRequired(message='input password')])
    remember_me = BooleanField(u'记住我')
    submit = SubmitField(u'登录')
@app.route('/',methods=['GET','POST'])
def login():
    form = LoginForm()
    result = u"请登录"
    if form.validate_on_submit(): 
    	result = u"欢迎你,"+ form.username.data
    	return redirect(url_for('mainpage',result = result))
    return render_template('login.html',title='登录',form=form, result = result)

然后在login.html中使用bootstrap模板进行渲染:

{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<div class="alert alert-warning">{{result}}</div>
<div class="col-md-4">
    {{ wtf.quick_form(form) }}
</div>
{% endblock %}

4. 数据库

这里用最最最简单的sqlite,centos系统自带。

4.1 ORM模型

使用flask_sqlalchemy建立ORM模型,用对象化的方法操作数据库。使用之前需要安装flask_sqlalchemy。
简单例子如下:

from flask_sqlalchemy import SQLAlchemy
import sqlite3
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
    SQLALCHEMY_DATABASE_URI = 'sqlite:///'+os.path.join(basedir,'static/data.sqlite3')
    SQLALCHEMY_TRACK_MODIFICATIONS=True
    SQLALCHEMY_COMMIT_ON_TEARDOWN=True

app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)

class User(db.Model):
    __tablename__='user'
    id = db.Column(db.Integer, primary_key = True)
    phone = db.Column(db.String(64),nullable=False)
    pw = db.Column(db.String(64),nullable=False)
    def __repr__(self):
        return '<User %r>'%self.phone

@app.route('/',methods=['GET','POST'])
def login():
    form = LoginForm()
    result = u"请登录"
    if form.validate_on_submit():        
        try:
            user = User.query.filter_by(phone=form.username.data).first()
            if user is None:
                result = u'没有此用户'
            else:
                if user.pw == form.password.data:
                    session['user'] = form.username.data
                    return redirect(url_for('schedule'))
                else:
                    result = u'密码错误'
        except Exception as err:
            result = err
    return render_template('login.html',title='登录',form=form,result = result)

其中db对象表示创建了一个新的SQLAlchemy类的实例,使用这个对象可以创建数据库、创建表、对表进行数据增删改查的操作。
既然是关系型数据库,那么表达关系是非常重要的内容,下面是上面例子的拓展:

class User(db.Model):
    __tablename__='user'
    id = db.Column(db.Integer, primary_key = True)
    phone = db.Column(db.String(64),nullable=False)
    pw = db.Column(db.String(64),nullable=False)
    operations = db.relationship('Operation',backref='user',lazy='dynamci')
    def __repr__(self):
        return '<User %r>'%self.phone

class Operation(db.Model):
	__tablename__='operation'
	id = db.Column(db.Integer, primary_key = True)
	action = db.Column(db.Integer)
	time = db.Column(db.DateTime)
	user_id = db.Column(db.Integer,db.ForeignKey('user.id'))

在Operation类中,对字段添加ForeignKey的声明,就可以将两张表连接起来了;在User表中添加一个db.relationship的声明,就可以直接连接user对象(而不仅仅是user_id)。

4.2 sqlite操作

在创建了ORM模型后,我们可以直接使用它进行sqlite的操作。
首先打开python shell,执行下面的语句:

from schedule import db, User, Operation#这里导入放置ORM模型的py文件
db.create_all() #根据config中声明的地址创建数据库,并根据ORM的类创建表。
user1 = User(phone = '15000000000',pw = '123456')
user2 = User(phone = '18900000000',pw = '654321')
oper1_1 = Operation(action = 1, time = '2018-11-12 12:23:30',user = user1)
oper1_2 = Operation(action = 2, time = '2018-11-12 15:13:20',user = user1)

通过数据库的会话管理对数据库进行操作

db.session.add_all([user1,user2,oper1_1,oper1_2])
db.session.commit()

增、改都使用add/add_all方法,删除用delete方法,查询用query方法,例如:

>>> User.query.all()
>>> User.query.filter_by(phone=form.username.data).first()
>>> user1.operations.filter_by(action = 1).count()

可以使用DDL语句直接在python中进行查询。直接输入sqlite3 + 数据库文件可以进入shell界面,使用SQL命令即可进行查询:
在这里插入图片描述

.header on 显示表头
.mode column 列显示方式
.databases 显示数据库
.tables 显示表名

猜你喜欢

转载自blog.csdn.net/kittyzc/article/details/84326227