flask学习笔记

 

1、模板

模板渲染

Flask 配备了 Jinja2 模板引擎,通过使用 render_template() 方法来渲染模板,render_template函数把Jinja2模板引擎集成到了程序中。

render_template函数的第一个参数是模板的文件名。随后的参数都是键值对,表示模板中变量对应的真实值。

from flask import render_template

@app.route('/hello/')
@app.route('/hello/<name>')
def hello(name=None):
    return render_template('hello.html', name=name)

hello.html

<!doctype html>
<title>Hello from Flask</title>
{% if name %}
  <h1>Hello {{ name }}!</h1>
{% else %}
  <h1>Hello World!</h1>
{% endif %}

模板继承

模板继承允许你创建一个基础的骨架模板, 这个模板包含您网站的通用元素,并且定义子模板可以重载的 blocks 。

基础模板

在这个叫做 layout.html 的模板中定义了一个简单的 HTML 文档骨架,你可以将这个骨架用作一个简单的双栏页面。而子模板负责填充空白的 block,在这个例子中,使用 {% block %} 标签定义了四个子模板可以重载的块。 block 标签所做的的所有事情就是告诉模板引擎: 一个子模板可能会重写父模板的这个部分。

layout.html 

<!doctype html>
<html>
  <head>
    {% block head %}
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
    <title>{% block title %}{% endblock %} - My Webpage</title>
    {% endblock %}
  </head>
<body>
  <div id="content">{% block content %}{% endblock %}</div>
  <div id="footer">
    {% block footer %}
    &copy; Copyright 2010 by <a href="http://domain.invalid/">you</a>.
    {% endblock %}
  </div>
</body>

子模板

{% extends %} 是这个例子的关键,它会告诉模板引擎这个模板继承自另一个模板的, 模板引擎分析这个模板时首先会定位其父父模板。extends 标签必须是模板的首个标签。 想要渲染父模板中的模板需要使用 {{ super() }}。

{% extends "layout.html" %}
{% block title %}Index{% endblock %}
{% block head %}
  {{ super() }}
  <style type="text/css">
    .important { color: #336699; }
  </style>
{% endblock %}
{% block content %}
  <h1>Index</h1>
  <p class="important">
    Welcome on my awesome homepage.
{% endblock %}

2、Flask-Bootstrap

Flask-Bootstrap 把 Bootstrap 打包进一个 扩展,这个扩展主要由一个叫“bootstrap”的蓝本(blueprint)组成。它也可以创建链接从一个CDN上引用Bootstrap资源。

初始化Flask-Bootstrap

from flask.ext.bootstrap import Bootstrap 
# ...
bootstrap = Bootstrap(app)

3、Flask-SQLAlchemy

Flask-SQLAlchemy是一个Flask扩展,简化了在Flask程序中使用SQLAlchemy的操作。SQLAlchemy是一个很强大的关系型数据库框架,支持多种数据库后台。SQLAlchemy提供了高层ORM,也提供了使用数据库原生SQL的低层功能。

安装

pip install flask-sqlalchemy

在Flask-SQLAlchemy中,数据库使用URL指定。最流行的数据库引擎采用的数据库URL格式如下

 

hostname表示MySQL服务所在的主机,可以是本地主机(localhost),也可以是远程服务器。数据库服务器上可以托管多个数据库,因此database表示要使用的数据库名。如果数据库需要进行认证,username和password表示数据库用户密令。

配置数据库

from flask.ext.sqlalchemy import SQL
Alchemybasedir = os.path.abspath(os.path.dirname(__file__))
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] =\    'sqlite:///' + os.path.join(basedir, 'data.sqlite')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
db = SQLAlchemy(app)

db对象是SQLAlchemy类的实例,表示程序使用的数据库,同时还获得了Flask-SQLAlchemy提供的所有功能。

定义Role和User模型

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    def __repr__(self):
        return '<Role %r>' % self.name
class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    def __repr__(self):
        return '<User %r>' % self.username

类变量__tablename__定义在数据库中使用的表名。,其余的类变量都是该模型的属性,被定义为db.Column类的实例,db.Column类构造函数的第一个参数是数据库列和模型属性的类型。

关系

db.relationship()的第一个参数表明这个关系的另一端是哪个模型。

class Role(db.Model):
# ...
users = db.relationship('User', backref='role')
class User(db.Model):
# ...
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

db.relationship()中的backref参数向User模型中添加一个role属性,从而定义反向关系。这一属性可替代role_id访问Role模型,此时获取的是模型对象,而不是外键的值。

创建表 

首先,我们要让Flask-SQLAlchemy根据模型类创建数据库。方法是使用db.create_all()函数:

(venv) $ python hello.py shell
>>> from hello import db
>>> db.create_all()

插入行 

>>> from hello import Role, User
>>> admin_role = Role(name='Admin')
>>> mod_role = Role(name='Moderator')
>>> user_role = Role(name='User')
>>> user_john = User(username='john', role=admin_role)
>>> user_susan = User(username='susan', role=user_role)
>>> user_david = User(username='david', role=user_role)

通过数据库会话管理对数据库所做的改动,在Flask-SQLAlchemy中,会话由db.session表示。准备把对象写入数据库之前,先要将其添加到会话中:

>>> db.session.add_all([admin_role, mod_role, user_role,...     user_john, user_susan, user_david])

为了把对象写入数据库,我们要调用commit()方法提交会话:

>>> db.session.commit()

 修改行

>>> admin_role.name = 'Administrator'
>>> db.session.add(admin_role)
>>> db.session.commit()

 删除行 

>>> db.session.delete(mod_role)  
>>> db.session.commit()

查询行 

Flask-SQLAlchemy为每个模型类都提供了query对象。最基本的模型查询是取回对应表中的所有记录:

>>> Role.query.all()[<Role u'Administrator'>, <Role u'User'>]
>>> User.query.all()[<User u'john'>, <User u'susan'>, <User u'david'>]

使用过滤器可以配置query对象进行更精确的数据库查询。下面这个例子查找角色为"User"的所有用户:

>>> User.query.filter_by(role=user_role).all()[<User u'susan'>, <User u'david'>]

若要查看SQLAlchemy为查询生成的原生SQL查询语句,只需把query对象转换成字符串:

>>> str(User.query.filter_by(role=user_role))'SELECT users.id AS users_id, users.username AS users_username,users.role_id AS users_role_id FROM users WHERE :param_1 = users.role_id'

可在query对象上调用的常用过滤器 

 

 在查询上应用指定的过滤器后,通过调用all()执行查询,以列表的形式返回结果。除了all()之外,还有其他方法能触发查询执行。

4、Flask-Mail

安装

(venv) $ pip install flask-mail

使用Google Gmail账户发送电子邮件。

import os
# ...
app.config['MAIL_SERVER'] = 'smtp.googlemail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = os.environ.get('MAIL_USERNAME')
app.config['MAIL_PASSWORD'] = os.environ.get('MAIL_PASSWORD')

初始化Flask-Mail

from flask.ext.mail import Mail
mail = Mail(app)

 在Python shell中发送电子邮件

(venv) $ python hello.py shell
>>> from flask.ext.mail import Message
>>> from hello import mail
>>> msg = Message('test subject', sender='you@example.com',
...     recipients=['you@example.com'])
>>> msg.body = 'text body'
>>> msg.html = '<b>HTML</b> body'
>>> with app.app_context():
...    mail.send(msg)...

在程序中集成发送电子邮件功能

from flask.ext.mail import Message
app.config['FLASKY_MAIL_SUBJECT_PREFIX'] = '[Flasky]'
app.config['FLASKY_MAIL_SENDER'] = 'Flasky Admin <flasky@example.com>'
def send_email(to, subject, template, **kwargs):
    msg = Message(app.config['FLASKY_MAIL_SUBJECT_PREFIX'] + subject,sender=app.config['FLASKY_MAIL_SENDER'], recipients=[to])
    msg.body = render_template(template + '.txt', **kwargs)
    msg.html = render_template(template + '.html', **kwargs)
    mail.send(msg)

这个函数用到了两个程序特定配置项,分别定义邮件主题的前缀和发件人的地址。send_email函数的参数分别为收件人地址、主题、渲染邮件正文的模板和关键字参数列表。指定模板时不能包含扩展名,这样才能使用两个模板分别渲染纯文本正文和富文本正文。调用者将关键字参数传给render_template()函数,以便在模板中使用,进而生成电子邮件正文。

5、大型程序的结构

配置选项

config.py:程序的配置

import os
basedir = os.path.abspath(os.path.dirname(__file__))

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'                    
    SQLALCHEMY_COMMIT_ON_TEARDOWN = True
    FLASKY_MAIL_SUBJECT_PREFIX = '[Flasky]'
    FLASKY_MAIL_SENDER = 'Flasky Admin <flasky@example.com>'
    FLASKY_ADMIN = os.environ.get('FLASKY_ADMIN')

    @staticmethod
    def init_app(app):
        pass

class DevelopmentConfig(Config):
    DEBUG = True
    MAIL_SERVER = 'smtp.googlemail.com'
    MAIL_PORT = 587
    MAIL_USE_TLS = True
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')
    SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \        'sqlite:///' + os.path.join(basedir, 'data-dev.sqlite')

class TestingConfig(Config):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \        'sqlite:///' + os.path.join(basedir, 'data-test.sqlite')

class ProductionConfig(Config):
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \        'sqlite:///' + os.path.join(basedir, 'data.sqlite')

config = {
    'development': DevelopmentConfig,
    'testing': TestingConfig,
    'production': ProductionConfig,
    'default': DevelopmentConfig}

基类Config中包含通用配置,子类分别定义专用的配置。

配置类可以定义init_app()类方法,其参数是程序实例。在这个方法中,可以执行对当前环境的配置初始化。现在,基类Config中的init_app()方法为空。 

在这个配置脚本末尾,config字典中注册了不同的配置环境,而且还注册了一个默认配置(本例的开发环境)。

程序包

程序包用来保存程序的所有代码、模板和静态文件。我们可以把这个包直接称为app(应用),如果有需求,也可使用一个程序专用名字。templates和static文件夹是程序包的一部分,因此这两个文件夹被移到了app中。数据库模型和电子邮件支持函数也被移到了这个包中,分别保存为app/models.py和app/email.py。

使用程序工厂函数

程序的工厂函数在app包的构造文件中定义。

create_app()函数就是程序的工厂函数,接受一个参数,是程序使用的配置名。

配置类在config.py文件中定义,其中保存的配置可以使用Flaskapp.config配置对象提供的from_object()方法直接导入程序。

至于配置对象,则可以通过名字从config字典中选择。程序创建并配置好后,就能初始化扩展了。在之前创建的扩展对象上调用init_app()可以完成初始化过程。

app/__init__.py:程序包的构造文件

from flask import Flask, render_template
from flask.ext.bootstrap import Bootstrap
from flask.ext.mail import Mail
from flask.ext.moment import Moment
from flask.ext.sqlalchemy import SQLAlchemy
from config import config

bootstrap = Bootstrap()
mail = Mail()
moment = Moment()
db = SQLAlchemy()
def create_app(config_name):
    app = Flask(__name__)
    app.config.from_object(config[config_name])
    config[config_name].init_app(app)
    bootstrap.init_app(app)
    mail.init_app(app)
    moment.init_app(app)
    db.init_app(app)    # 附加路由和自定义的错误页面
    return app

 

蓝本

app/main/__init__.py:创建蓝本

from flask import Blueprint
main = Blueprint('main', __name__)
from . import views, errors

通过实例化一个Blueprint类对象可以创建蓝本。这个构造函数有两个必须指定的参数:蓝本的名字和蓝本所在的包或模块。和程序一样,大多数情况下第二个参数使用Python的__name__变量即可。

蓝本在工厂函数create_app()中注册到程序上

app/_init_.py:注册蓝本

def create_app(config_name):
    # ...    
from .main import main as main_blueprint
    app.register_blueprint(main_blueprint)
    return app

app/main/errors.py:蓝本中的错误处理程序

from flask import render_template
from . import main

@main.app_errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

@main.app_errorhandler(500)
def internal_server_error(e):
    return render_template('500.html'), 500

app/main/views.py:蓝本中定义的程序路由

from datetime import datetime
from flask import render_template, session, redirect, url_forfrom . 
import mainfrom .forms 
import NameFormfrom .. 
import dbfrom ..models 
import User

@main.route('/', methods=['GET', 'POST'])
def index():
    form = NameForm()
    if form.validate_on_submit():
        # ...
        return redirect(url_for('.index'))
    return render_template('index.html',
                           form=form, name=session.get('name'),
                           known=session.get('known', False),
                           current_time=datetime.utcnow())

启动脚本

manage.py:启动脚本

#!/usr/bin/env python
import os
from app import create_app, db
from app.models import User, Role
from flask.ext.script import Manager, Shell
from flask.ext.migrate import Migrate, MigrateCommand

app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)
migrate = Migrate(app, db)
def make_shell_context():
    return dict(app=app, db=db, User=User, Role=Role)

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

if __name__ == '__main__':
    manager.run()

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值