【002】基于Python的Flask Web应用框架(2)

最近在实验楼学习的python,笔记实际上都是上面的教程练习加上自己的理解。

在上次学习flask的基础上,这次用flask写了一个小博客,数据库是SQLite 3, 因为它足够应付这种规模的应用。对更大的应用使用 SQLAlchemy 比较好。

实现登录验证及博文展示(使用SQLite3)

这次使用的是PyChrm,不然每次都要在Shell中敲命令行(关键是不同应用切来切去太麻烦了)。

使用PyChrm创建project时有flask 的选项,创建好后自动创建好了static,templates文件夹以及.py文件,我的是这样的:

project

Web小应用的功能大概是这样:

  1. 创建数据库以及表。
  2. 连接数据库进入应用。
  3. 登录成功后可以直接写博文,保存在数据库中并显示到当前页面。

首先在project根目录下新建sql脚本文件

/schema.sql

drop table if exists entries;
create table entries 
(
  id integer primary key autoincrement,
  title string not null,
  text string not null
);

这个脚本将在python中调用运行,新建一个表entries,包括博文id(主键,以1为基数自增),标题title,正文text。

开始flaskr.py

/flask.py

#!/usr/bin/python
# -*- coding: utf8 -*-
from __future__ import with_statement
from contextlib import closing
# 导入所有的模块
import sqlite3
import sys
from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
reload(sys)
# 当网页中有中文时,就需要进行utf8编码,以便网页内容能够被浏览器解码正常显示
sys.setdefaultencoding('utf8')

# 配置文件
# SECRET_KEY是需要为了保持客户端的会话安全。最好是尽可能复杂。
# 也可使用密码随机生成器
# >>> import os
# >>> os.urandom(24)
DATABASE = '/tmp/flaskr.db'
DEBUG = True
SECRET_KEY = 'i like python'
USERNAME = 'admin'
PASSWORD = 'default'

# 创建应用
app = Flask(__name__)

# from_object()将会寻找给定的对象(如果它是一个字符串,则会导入它),搜寻里面定义的全部大写的变量。
# 在我们的这种情况中,配置文件就是我们上面写的几行代码。你也可以将他们分别存储到多个文件。
# 从配置文件中加载配置,用from_envvar(),替换from_object()
# app.config.from_envvar('FLASKR_SETTINGS', silent=True)
# 这种方法我们可以设置一个名为FLASKR_SETTINGS的环境变量来设定一个配置文件载入后是否覆盖默认值。
#静默开关silent=True告诉 Flask 不去关心这个环境变量键值是否存在。
app.config.from_object(__name__)

# 连接到指定数据库
def connect_db():
    return sqlite3.connect(app.config['DATABASE'])

# 初始化数据库
# 在应用运行之前需要在python shell中调用该函数创建数据库
# >>> from flaskr import init_db
# >>> init_db()
def init_db():
    # closing()函数允许我们在with块中保持数据库连接可用
    # 数据库连接对象‘db’提供一个数据库指针
    with closing(connect_db()) as db:
        with app.open_resource('schema.sql') as f:
            # db.cursor()是获得python执行sql命令的方法,也就是操作游标
            # executescript函数一次可以执行多条sql
            # db.cursor().executescript(f.read())为:python读取并执行全部SQL语句
            db.cursor().executescript(f.read())
        # commit()为提交修改
        db.commit()

# 使用before_request()装饰器的函数会在数据库连接请求之前被调用而且不带参数
# 使用after_request()装饰器的函数会在请求之后被调用且传入将要发给客户端的响应。
# 使用teardown_request()装饰器。它装饰的函数将在响应构造后执行,并不允许修改请求,返回的值会被忽略。
# 如果在请求已经被处理的时候抛出异常,它会被传递到每个函数,否则会传入一个None。
# 我们把当前的数据库连接保存在 Flask 提供的 g 特殊对象中。这个对象只能保存一次请求的信息,
# 并且在每个函数里都可用。不要用其它对象来保存信息,因为在多线程环境下将不可行。
# 特殊的对象 g 在后台有一些神奇的机制来保证它在做正确的事情。
@app.before_request
def before_request():

    g.db = connect_db()

@app.teardown_request
def teardown_request(exception):

    g.db.close()

@app.route('/')
def show_entries():

    # 按照id列倒序形式取出数据库中的数据存入cur
    cur = g.db.execute('select title, text from entries order by id desc')
    # fetchall()方法返回查询到的所有记录
    entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]

    return render_template('show_entries.html', entries=entries)

@app.route('/add', methods=['POST'])
def add_entry():

    if not session.get('logged_in'):

        abort(401)
    g.db.execute('insert into entries (title, text) values (?, ?)',[request.form['title'], request.form['text']])

    g.db.commit()

    # 使用flash()方法来闪现一个消息,使用get_flashed_messages()能够获取消息,get_flashed_messages()也能用于模版中。
    # flash()闪现的消息在layout.html中通过get_flashed_message()中显示出来。
    flash('New entry was succesfully posted')

    return redirect(url_for('show_entries'))


@app.route('/login', methods=['GET', 'POST'])
def login():

    error = None

    if request.method == 'POST':

        if request.form['username'] != app.config['USERNAME']:

            error = 'Invalid username/用户不存在'

        elif request.form['password'] != app.config['PASSWORD']:

            error = 'Invalid password/密码错误'

        else:

            session['logged_in'] = True

            flash('You were logged in/您已经登录')

            return redirect(url_for('show_entries'))

    return render_template('login.html', error=error)

@app.route('/logout')
def logout():

    session.pop('logged_in', None)

    flash('You were logged out/您已经登出')

    return redirect(url_for('show_entries'))

if __name__ == "__main__":
    app.run()

模板和静态文件

/templates/layout.html

<!doctype html>
<title>Flaskr</title>
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
<div class=page>
    <h1>Flaskr</h1>
    <div class=metanav>
        {% if not session.logged_in %}
            <a href="{{ url_for('login') }}">log in/登录</a>
        {% else %}
            <a href="{{ url_for('logout') }}">log out/登出</a>
        {% endif %}
    </div>
    {% for message in get_flashed_messages() %}
        <div class=flash>{{ message }}</div>
    {% endfor %}
    {% block body %}
    {% endblock %}
</div>

/templates/login.html

{% extends "layout.html" %}
{% block body %}
    <h2>Login</h2>
    {% if error %}<p class=error><strong>Error:</strong> {{ error }}
    {% endif %}
    <form action="{{ url_for('login') }}" method=post class="myForm1">
        <dl>
            <dt>Username/账户:
            <dd><input type=text name=username>
            <dt>Password/密码:
            <dd><input type=password name=password>
            <dd><input type=submit value=Login/登录>
        </dl>
    </form>
{% endblock %}

/templates/show_entries.html

{% extends "layout.html" %}
{% block body %}
    {% if session.logged_in %}
        <form action="{{ url_for('add_entry') }}" method=post class=add-entry>
            <dl>
                <dt>Title/标题:
                    <dd><input type=text size=30 name=title>
                <dt>Text/内容:
                    <dd><textarea name=text rows=5 cols=40></textarea>
                <dd><input type=submit value=Share >
            </dl>
        </form>
        <ul class=entries>
        {% if not entries %}
            <li><em>Unbelievable.No entries here so far/您当前<strong>没有博客</strong>哟~</em>
        {% else %}
            {% for entry in entries %}
                <!--在模板中使用|safe过滤器, 否则 Jinja2 会确保特殊字符比如<或>被转义成等价的XML实体。-->
                <li><h2>{{ entry.title }}</h2>{{ entry.text|safe }}

            {% endfor %}
        {% endif %}
    {% else %}
        <li><em>Unbelievable.No Users so far/您当前<strong>没有登录</strong>哟~</em>
    {% endif %}
        </ul>
{% endblock %}

/static/style.css

body            { font-family: sans-serif; background: #eee; }
a, h1, h2       { color: #377BA8; }
h1, h2          { font-family: 'Georgia', serif; margin: 0; }
h1              { border-bottom: 2px solid #eee; }
h2              { font-size: 1.2em; }
.myForm1 input[type=submit]
{

    background-color: green;
    border-radius: 10px;
    border: none;
    margin-top: 10px;
    padding: 5px 10px 5px 10px;
    color: white;
}
.page           { margin: 2em auto; width: 35em; border: 5px solid #ccc;
                  padding: 0.8em; background: white; }
.entries        { list-style: none; margin: 0; padding: 0; }
.entries li     { margin: 0.8em 1.2em; }
.entries li h2  { margin-left: -1em; }
.add-entry      { font-size: 0.9em; border-bottom: 1px solid #ccc; }
.add-entry dl   { font-weight: bold; }
.add-entry input[type=submit]
{
    background-color: green;
    border-radius: 10px;
    border: none;
    margin-top: 10px;
    padding: 5px 10px 5px 10px;
    color: white;
}
.metanav        { text-align: right; font-size: 0.8em; padding: 0.3em;
                  margin-bottom: 1em; background: #fafafa; }
.flash          { background: #CEE5F5; padding: 0.5em;
                  border: 1px solid #AACBE2; }
.error          { background: #F0D6D6; padding: 0.5em; }

在Python 交互中调用init_db()函数创建数据库后运行Web应用

start

点击log in

login

正确输入登录信息,登录成功,初次运行没有文章

write

键入文章,点击share

show1

show2

注销登录

logout

flask的学习暂时就到这里,个人感觉用flask框架写Web应用很轻便,扩充空间大,非常适合新手进阶。

ps:在flask学习过程中发现有些时候project处于有中文的目录下时,css样式表就无法发挥作用,这里建议目录最好不要有中文。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值