Last active
September 12, 2018 06:52
-
-
Save sophana/6209de86c08bba0355c4a0bfa668839d to your computer and use it in GitHub Desktop.
sample single file templateless flask application that demonstrates flask_bootstrap, flask_wtform, flask_nav, flask_login, and dominate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
sample single file templateless flask application that demonstrates flask_bootstrap, flask_wtform, flask_nav, flask_login | |
uses dominate instead of templates | |
to use: (in virtual env) | |
pip install dominate Flask Flask-Bootstrap Flask-WTF flask-nav Flask-Login | |
python sample_dominate.py | |
''' | |
from flask import Flask, session, request, redirect, render_template_string, flash | |
from flask.sessions import SecureCookieSessionInterface | |
from flask_bootstrap import Bootstrap,bootstrap_find_resource, render_form | |
from flask_login import LoginManager, UserMixin, login_required, login_user, logout_user , current_user | |
from flask_wtf import FlaskForm | |
from wtforms import StringField,PasswordField,SubmitField | |
from wtforms.validators import DataRequired | |
import dominate as dom | |
import dominate.tags as t | |
from dominate.util import raw | |
from flask_nav import Nav | |
from flask_nav.elements import Navbar, View, Subgroup, Link, Text, Separator | |
from functools import wraps | |
app = Flask(__name__) | |
Bootstrap(app) | |
app.secret_key = "rAxIqk4mMZkc6VYWwndDDCNg5D6q0AUDs11pGENoNoeo3V1SWVebuOO5XizEevDxl3wVQHRDnp7skeoU" | |
app.session_interface = SecureCookieSessionInterface(); | |
# login form | |
class LoginForm(FlaskForm): | |
login = StringField('Login', validators=[DataRequired()]) | |
passwd = PasswordField('Passwd', validators=[DataRequired()]) | |
submit_button = SubmitField('Login') | |
# dominate tag which has no tag. useful for example to add js script at end of body | |
class noTag(t.html_tag): | |
def _render(self, sb, indent_level=1, indent_str=' ', pretty=True, xhtml=False): | |
pretty = self._render_children(sb, indent_level , indent_str, pretty, xhtml) | |
## flask form template rendering (render_form is unfortunately not finished) | |
formTemplate=''' | |
{%% import "bootstrap/wtf.html" as wtf %%} | |
{{ wtf.quick_form(form, form_type='%s'%s) }} | |
''' | |
def renderForm(form, formType='basic', extraArg='') : | |
return raw(render_template_string(formTemplate%(formType,extraArg),form=form)) | |
### nav | |
nav=Nav() | |
nav.init_app(app) | |
barGroup = Subgroup( # static subgroup | |
'Docs', | |
Link('Flask-Bootstrap', 'http://pythonhosted.org/Flask-Bootstrap'), | |
Link('Flask-AppConfig', 'https://github.com/mbr/flask-appconfig'), | |
Link('Flask-Debug', 'https://github.com/mbr/flask-debug'), | |
Separator(), | |
Text('Bootstrap'), | |
Link('Getting started', 'https://v4-alpha.getbootstrap.com/getting-started/introduction/'), | |
Link('Layout', 'https://v4-alpha.getbootstrap.com/layout/overview/'), | |
Link('Content', 'https://v4-alpha.getbootstrap.com/content/reboot/'), | |
Link('Components', 'https://v4-alpha.getbootstrap.com/components/alerts/'), | |
Link('Utilities', 'https://v4-alpha.getbootstrap.com/utilities/borders/'), | |
Link('About', 'https://v4-alpha.getbootstrap.com/about/history/'), | |
) | |
def topBar(): | |
# dynamic nav bar | |
return Navbar(*( | |
[ View('Flask-Bootstrap', '.hello') | |
, View('Dashboard', '.dash') | |
] | |
+ [ View('Logout', '.logout')] * current_user.is_authenticated | |
+ [ Text('Welcome %s'%('guest' if not current_user.is_authenticated else current_user.id)) | |
, barGroup | |
] | |
)) | |
## flask_login minimal user class | |
class User(UserMixin): | |
def __init__(self,id): | |
self.id = id | |
login_manager = LoginManager() | |
login_manager.init_app(app) | |
login_manager.login_view = "login" | |
@login_manager.user_loader | |
def load_user(userid): | |
return User(userid) | |
# this is our bootstrap document template | |
def getDoc() : | |
doc = dom.document(title="mypage") | |
with doc.head: | |
t.meta(name="viewport",content="width=device-width, initial-scale=1.0") | |
t.link(href=bootstrap_find_resource('css/bootstrap.css', cdn='bootstrap'),rel="stylesheet") | |
doc.body, doc.bodyEnd = doc.body.add(t.div(_class="container"), noTag(t.comment("bodyEnd"))) | |
with doc.body: | |
topBar().render() | |
# TBD: display flash messages | |
with doc.bodyEnd: | |
t.script(src=bootstrap_find_resource('jquery.js', cdn='jquery')) | |
t.script(src=bootstrap_find_resource('js/bootstrap.js', cdn='bootstrap')) | |
return doc | |
#decorator that calls our template | |
def stdDoc(func): | |
@wraps(func) | |
def wrap(): | |
doc=getDoc() | |
with doc.body: | |
r=func() | |
if r is not None: | |
return r | |
return doc.render() | |
return wrap | |
@app.route('/login',methods=['GET','POST']) | |
@stdDoc | |
def login(): | |
form = LoginForm(request.form) | |
if request.method=='POST' and form.validate_on_submit(): # to get error messages to the browser | |
if form.login.data == form.passwd.data: | |
user=User(form.login.data) | |
login_user(user) | |
flash("Login Ok!") | |
return redirect(request.args.get("next")) | |
else: | |
form.passwd.errors=["wrong password"] | |
with t.div(_class="jumbotron"): | |
t.h1("Please login") | |
t.p("Password must equal to login in this example") | |
renderForm(form, formType='horizontal') | |
@app.route("/logout") | |
def logout(): | |
logout_user() # call logout_user before getDoc to update the navbar | |
doc=getDoc() | |
with doc.body: | |
t.h1("Logout done") | |
return doc.render() | |
@app.route("/dash") | |
@login_required | |
@stdDoc | |
def dash(): | |
t.h1("Welcome %s"%current_user.id) | |
@app.route('/') | |
@stdDoc | |
def hello(): | |
t.h1("Welcome!") | |
if __name__ == '__main__': | |
app.run(debug=True, host="0.0.0.0") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment