forked from orbit-oss/flask
Added mini blogging application as Flask example.
This should become the tutorial.
This commit is contained in:
parent
2d9bb69272
commit
c33675f025
7 changed files with 241 additions and 0 deletions
103
examples/flaskr/flaskr.py
Normal file
103
examples/flaskr/flaskr.py
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Flaskr
|
||||
~~~~~~
|
||||
|
||||
A microblog example application written as Flask tutorial with
|
||||
Flask and sqlite3.
|
||||
|
||||
:copyright: (c) 2010 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
from __future__ import with_statement
|
||||
import time
|
||||
import sqlite3
|
||||
from contextlib import closing
|
||||
from flask import Flask, request, session, g, redirect, url_for, abort, \
|
||||
render_template, flash
|
||||
from werkzeug import secure_filename
|
||||
|
||||
# configuration
|
||||
DATABASE = '/tmp/flaskr.db'
|
||||
DEBUG = True
|
||||
SECRET_KEY = 'development key'
|
||||
USERNAME = 'admin'
|
||||
PASSWORD = 'default'
|
||||
|
||||
# create our little application :)
|
||||
app = Flask(__name__)
|
||||
app.secret_key = SECRET_KEY
|
||||
app.debug = DEBUG
|
||||
|
||||
|
||||
def connect_db():
|
||||
"""Returns a new connection to the database."""
|
||||
return sqlite3.connect(DATABASE)
|
||||
|
||||
|
||||
def init_db():
|
||||
"""Creates the database tables."""
|
||||
with closing(connect_db()) as db:
|
||||
with app.open_resource('schema.sql') as f:
|
||||
db.cursor().executescript(f.read())
|
||||
db.commit()
|
||||
|
||||
|
||||
@app.request_init
|
||||
def before_request():
|
||||
"""Make sure we are connected to the database each request. Also
|
||||
set `g.logged_in` to `True` if we are logged in.
|
||||
"""
|
||||
g.db = connect_db()
|
||||
g.logged_in = session.get('logged_in', False)
|
||||
|
||||
|
||||
@app.request_shutdown
|
||||
def after_request(response):
|
||||
"""Closes the database again at the end of the request."""
|
||||
g.db.close()
|
||||
return response
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def show_entries():
|
||||
cur = g.db.execute('select title, text from entries order by id desc')
|
||||
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 g.logged_in:
|
||||
abort(401)
|
||||
g.db.execute('insert into entries (title, text) values (?, ?)',
|
||||
[request.form['title'], request.form['text']])
|
||||
g.db.commit()
|
||||
flash('New entry was successfully 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'] != USERNAME:
|
||||
error = 'Invalid username'
|
||||
elif request.form['password'] != 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()
|
||||
64
examples/flaskr/flaskr_tests.py
Normal file
64
examples/flaskr/flaskr_tests.py
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Flaskr Tests
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Tests the Flaskr application.
|
||||
|
||||
:copyright: (c) 2010 by Armin Ronacher.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import flaskr
|
||||
import unittest
|
||||
import tempfile
|
||||
|
||||
|
||||
class FlaskrTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""Before each test, set up a blank database"""
|
||||
self.db = tempfile.NamedTemporaryFile()
|
||||
self.app = flaskr.app.test_client()
|
||||
flaskr.DATABASE = self.db.name
|
||||
flaskr.init_db()
|
||||
|
||||
def login(self, username, password):
|
||||
return self.app.post('/login', data=dict(
|
||||
username=username,
|
||||
password=password
|
||||
), follow_redirects=True)
|
||||
|
||||
def logout(self):
|
||||
return self.app.get('/logout', follow_redirects=True)
|
||||
|
||||
# testing functions
|
||||
|
||||
def test_login_logout(self):
|
||||
"""Make sure login and logout works"""
|
||||
rv = self.login(flaskr.USERNAME, flaskr.PASSWORD)
|
||||
assert 'You were logged in' in rv.data
|
||||
rv = self.logout()
|
||||
assert 'You were logged out' in rv.data
|
||||
rv = self.login(flaskr.USERNAME + 'x', flaskr.PASSWORD)
|
||||
assert 'Invalid username' in rv.data
|
||||
rv = self.login(flaskr.USERNAME, flaskr.PASSWORD + 'x')
|
||||
assert 'Invalid password' in rv.data
|
||||
|
||||
def test_messages(self):
|
||||
"""Test that messages work"""
|
||||
# start with a blank state
|
||||
rv = self.app.get('/')
|
||||
assert 'No entries here so far' in rv.data
|
||||
self.login(flaskr.USERNAME, flaskr.PASSWORD)
|
||||
rv = self.app.post('/add', data=dict(
|
||||
title='<Hello>',
|
||||
text='<strong>HTML</strong> allowed here'
|
||||
), follow_redirects=True)
|
||||
assert 'No entries here so far' not in rv.data
|
||||
self.login(flaskr.USERNAME, flaskr.PASSWORD)
|
||||
assert '<Hello>' in rv.data
|
||||
assert '<strong>HTML</strong> allowed here' in rv.data
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
6
examples/flaskr/schema.sql
Normal file
6
examples/flaskr/schema.sql
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
drop table if exists entries;
|
||||
create table entries (
|
||||
id integer primary key autoincrement,
|
||||
title string not null,
|
||||
text string not null
|
||||
);
|
||||
16
examples/flaskr/static/style.css
Normal file
16
examples/flaskr/static/style.css
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
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; }
|
||||
div.metanav { text-align: right; font-size: 0.8em; background: #fafafa;
|
||||
padding: 0.3em; margin-bottom: 1em; }
|
||||
ul.entries { list-style: none; margin: 0; padding: 0; }
|
||||
ul.entries li { margin: 0.8em 1.2em; }
|
||||
ul.entries li h2 { margin-left: -1em; }
|
||||
div.page { margin: 2em auto; width: 35em; border: 5px solid #ccc;
|
||||
padding: 0.8em; background: white; }
|
||||
form.add-entry { font-size: 0.9em; border-bottom: 1px solid #ccc; }
|
||||
form.add-entry dl { font-weight: bold; }
|
||||
div.flash { background: #CEE5F5; padding: 0.5em; border: 1px solid #AACBE2; }
|
||||
p.error { background: #F0D6D6; padding: 0.5em; }
|
||||
17
examples/flaskr/templates/layout.html
Normal file
17
examples/flaskr/templates/layout.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<!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 g.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>
|
||||
14
examples/flaskr/templates/login.html
Normal file
14
examples/flaskr/templates/login.html
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{% 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>
|
||||
<dl>
|
||||
<dt>Username:
|
||||
<dd><input type=text name=username>
|
||||
<dt>Password:
|
||||
<dd><input type=passowrd name=password>
|
||||
<dd><input type=submit value=Login>
|
||||
</dl>
|
||||
</form>
|
||||
{% endblock %}
|
||||
21
examples/flaskr/templates/show_entries.html
Normal file
21
examples/flaskr/templates/show_entries.html
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{% extends "layout.html" %}
|
||||
{% block body %}
|
||||
{% if g.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>
|
||||
{% endif %}
|
||||
<ul class=entries>
|
||||
{% for entry in entries %}
|
||||
<li><h2>{{ entry.title }}</h2>{{ entry.text|safe }}
|
||||
{% else %}
|
||||
<li><em>Unbelievable. No entries here so far</em>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
Loading…
Add table
Add a link
Reference in a new issue