I am trying to take a modular approach to designing my Flask App.
So each module as multiple routes. See below
Templates folder
Contents of my home_routes.py
from flask import Blueprint, request, session, abort
from flask import render_template
def home_blueprints(app):
home_routes = Blueprint("home_routes", __name__, template_folder='../../templates', static_folder='../../static')
#home_routes.route('/home/Links')
def links():
return render_template('links.html')
#home_routes.route('/home/Confirmation')
def confirmation():
return render_template('Confirmation.html')
#home_routes.route('/')
def main():
return render_template('main.html')
#home_routes.route('/home/Contactus', methods=['GET', 'POST'])
def contact():
if request.method == "POST":
token = session.pop('_csrf_token', None)
if not token or token != request.form.get('_csrf_token'):
abort(403)
return render_template('GoogleForm.html')
app.register_blueprint(home_routes)
Contents of believe_routes.py
from flask import Blueprint
from flask import render_template
def believe_blueprints(app):
believe_routes = Blueprint("believe_routes", __name__, template_folder='../../templates', static_folder='../../static')
#believe_routes.route('/home/Believe/Truth_About_God')
def truth_about_God():
return render_template('The_Truth_Concerning_God.html')
#believe_routes.route('/home/Believe/Truth_We_Believe')
def the_truth_we_beleive():
return render_template('The_Truth_We_Believe.html')
#believe_routes.route('/home/Believe/Truth_About_Christ')
def truth_about_christ():
return render_template('The_Truth_About_Christ.html')
#believe_routes.route('/home/Believe/Truth_About_Church')
def truth_about_church():
return render_template('The_Truth_About_Church.html')
#believe_routes.route('/home/Believe/Truth_About_Salvation')
def truth_about_salvation():
return render_template('The_Truth_About_Salvation.html')
#believe_routes.route('/Believe')
def truth_we_believe():
return render_template('Truth_We_Believe.html')
app.register_blueprint(believe_routes)
Contents of init.py
from home_routes import home_blueprints
from believe_routes import believe_blueprints
def configure_blueprints(app):
home_blueprints(app)
believe_blueprints(app)
Only the home_routes work. The URLs in the believe_routes do not work. I get a 404
INFO 2017-05-26 18:01:44,325 module.py:813] default: "GET /home/Believe/Truth_About_Christ HTTP/1.1" 404 233
I am calling configure_blueprints(app) from create_app which is then called from main.py.
Any thoughts please.
the 404 is not for the template reason, maybe you can try this code to view whether blueprint is registed to flask instance, and you can put your output back for more details...
#!/usr/bin/env python
# encoding: utf-8
from flask import Flask
from home_routes import home_blueprints
from believe_routes import believe_blueprints
app = Flask('demo')
def configure_blueprints(app):
home_blueprints(app)
believe_blueprints(app)
configure_blueprints(app)
print(app.url_map)
i hope this would help you ..
Related
I am facing a very weird Issue, In my Flask App when index route (https://sitename.com/) is called everything is fine, but as i navigate to a route like https://sitename.com/about it shows 404 Error, even when About route is created in main.py . This App works all perfect in localhost:5000 but when I deployed it too a VPS It is showing that Error of showing 404 on every route
My main.py
from os import environ
from flask import Flask, redirect, render_template, request, url_for
import requests
import json
import datetime
def getUserData(route):
if request.headers.getlist("X-Forwarded-For"):
ip = request.headers.getlist("X-Forwarded-For")[0]
else:
ip = request.remote_addr
with open("users.txt", "a") as f:
f.write(f"Page Visited: {route}\n")
f.write(f"User Agent: {request.headers.get('User-Agent')}\n")
f.write(f"Remote Addr: {ip}\n")
f.write(f"DateTime: {datetime.datetime.now()}\n")
f.write(f"\n\n\n")
app = Flask(__name__)
app.debug = True
# Website
#app.route('/')
def index():
getUserData("Index Page")
return render_template('index.html')
#app.route('/gallery')
def gallery():
getUserData("Gallery")
return render_template('pages/gallery.html')
#app.route('/faqs')
def faqs():
getUserData("FAQs")
return render_template('pages/faqs.html')
#app.route('/about')
def about():
getUserData("About")
return render_template('pages/about.html')
#app.route('/contact')
def contact():
getUserData("Contact")
return render_template('pages/contact.html')
# 404 Handling
#app.errorhandler(404)
def not_found(e):
getUserData("404 Page")
return render_template("pages/404.html")
if __name__ == '__main__':
app.run()
The get method on user works if the # api.add_resource(User, '/user/')
line is uncommented, and the other api.add_resource is.
The inverse of that is true to make the post method work.
How can I get both of these paths to work?
from flask import Flask, request
from flask.ext.restful import reqparse, abort, Api, Resource
import os
# set the project root directory as the static folder, you can set others.
app = Flask(__name__)
api = Api(app)
class User(Resource):
def get(self, userid):
print type(userid)
if(userid == '1'):
return {'id':1, 'name':'foo'}
else:
abort(404, message="user not found")
def post(self):
# should just return the json that was posted to it
return request.get_json(force=True)
api.add_resource(User, '/user/')
# api.add_resource(User, '/user/<string:userid>')
if __name__ == "__main__":
app.run(debug=True)
Flask-Restful supports registering multiple URLs for a single resource. Simply provide both URLs when you register the User resource:
api.add_resource(User, '/user/', '/user/<userid>')
I have a not-logged-in module/blueprint, welcome, and a logged-in blueprint, home. I want a user with a valid session to go to home.index, and a user that is a guest to go to welcome.index. However, I am running into issues because both of those functions route to the same URL, /.
How can I make this functionality possible? I have tried adding:
if(logged_in():
redirect(url_for('home.index'))
to index() in the welcome blueprint, but this of course just causes a circular redirect, because the URL for home.index is the same as welcome.index.
I have also tried to only define welcome.index if logged_in() is true. However, that causes issues because there are other links on the site that link to welcome.index, and if the user is logged in, those cause errors as welcome.index technically no longer exists.
Edit
I am seeing this error AttributeError: 'Blueprint' object has no attribute 'index' from this code:
from flask import Flask, session, g
from modules.welcome import welcome
from modules.home import home as home
from modules.home import index
from modules.welcome import index
app = Flask(__name__)
app.config.from_pyfile('config.cfg')
app.register_blueprint(welcome)
app.register_blueprint(home)
#app.route('/', methods=['GET', 'POST'])
def index():
if 'user_id' in session:
return home.index()
else:
return welcome.index()
Edit #2: Blueprints code
Code in modules/home.py:
from flask import Blueprint, render_template, redirect, url_for, request, session, g
from models.User import User
from helpers.login import *
home = Blueprint('home', __name__)
def index():
return render_template('home/index.html')
Code in modules/welcome.py:
from flask import Blueprint, render_template, redirect, url_for, request, session, g
import md5
from models.User import User
from helpers.login import *
welcome = Blueprint('welcome', __name__)
def index():
alert, email = None, None
if request.method == 'POST' and not logged_in():
email = request.form['email']
password_salt = md5.new(request.form['password']).hexdigest()
user = User.query.filter_by(email=email , password_salt=password_salt).first()
if user is None:
alert = "Wrong username or password!"
else:
session['user_id'] = user.id
return redirect(url_for('home.index'))
return render_template('welcome/index.html', alert=alert, email=email)
#welcome.route('/about')
def about():
return render_template('welcome/about.html')
#welcome.route('/tandp')
def tandp():
return render_template('welcome/tandp.html')
#welcome.route('/logout')
def logout():
session.pop('user_id', None)
return redirect(url_for('welcome.index'))
#welcome.route('/register')
def register():
error = None
return "HI"
Split up your methods, test for logged status and then call the proper function (adding the params you need on each):
from ????? import app
from ????? import logged_in
import home.index
import welcome.index
#app.route('/')
def your_basic_index_view():
if logged_in():
return home.index()
else:
return welcome.index()
Or do the same with a decorator. You won't be able to use a single route pointing conditionally to two different views.
EDIT:
Try the following:
from flask import Flask, session, g
from modules.welcome import welcome
from modules.home import home as home
from modules.home import index as h_index
from modules.welcome import index as w_index
app = Flask(__name__)
app.config.from_pyfile('config.cfg')
app.register_blueprint(welcome)
app.register_blueprint(home)
#app.route('/', methods=['GET', 'POST'])
def index():
if 'user_id' in session:
return h_index()
else:
return w_index()
I am building a simple extension for flask and have a problem with the url_for function not being able to build the urls within the extension.
Can somebody help me figure out what I am missing here?
I simplified the code to demonstrate the issue (all of the url_for calls raise a werkzeug BuildError exception):
import flask
import flask.views
import logging
logging.basicConfig(level=logging.DEBUG)
class MyFlaskExt(object):
def __init__(self, app=None):
if app is not None:
self.init_app(app)
def init_app(self, app):
self.blueprint = flask.Blueprint('myext', __name__, static_folder='static', template_folder='templates')
self.blueprint.add_url_rule('/', view_func=RootView.as_view('root'), endpoint='root')
self.blueprint.add_url_rule('/var/<somevar>', view_func=VarView.as_view('var'), endpoint='var')
self.blueprint.add_url_rule('/novar', view_func=NoVarView.as_view('novar'), endpoint='novar')
app.register_blueprint(self.blueprint)
class RootView(flask.views.View):
def dispatch_request(self):
logging.debug(flask.url_for('novar'))
logging.debug(flask.url_for('novar', _external=True))
return flask.redirect(flask.url_for('var', somevar='test'))
class VarView(flask.views.View):
def dispatch_request(self, somevar):
return "SUCCESS! ({})".format(somevar)
class NoVarView(flask.views.View):
def dispatch_request(self):
return "SUCCESS!"
if __name__ == '__main__':
app = flask.Flask(__name__)
app.debug = True
my_ext = MyFlaskExt()
my_ext.init_app(app)
logging.debug(app.url_map)
app.run()
Blueprint endpoints are registered under the name of the Blueprint. If I remember correctly you will either need to prepend your url_for calls with "." (if they will all be operating under the same blueprint) or use the full name:
def dispatch_request(self):
logging.debug(flask.url_for('.novar'))
logging.debug(flask.url_for('.novar', _external=True))
return flask.redirect(flask.url_for('.var', somevar='test'))
I have a question regarding blueprints. I have an app which is structured like this
app
/run.py
/APP
/__init__.py
/VIEWS
/__init__.py
/general.py
/crud.py
this is the code http://pastebin.com/bsHsTGAP
run.py
from overwatch import app
app.run()
__init__.py
from flask import Flask, session, g, render_template, request, redirect, url_for, Response
import websiteconfig as config
from flaskext.principal import Identity, Principal, RoleNeed, UserNeed, \
Permission, identity_changed, identity_loaded
app = Flask(__name__)
app.debug = config.DEBUG
app.secret_key = config.SECRET_KEY
principals = Principal(app)
principals._init_app(app)
#app.errorhandler(404)
def not_found(error):
return render_template('404.html'), 404
#app.errorhandler(403)
def page_not_found(e):
session['redirected_from'] = request.url
return redirect(url_for('crud.login'))
# handle login failed
#app.errorhandler(401)
def page_not_found(e):
return Response('<p>Login failed</p>')
from overwatch.views import general
from overwatch.views import crud
app.register_blueprint(general.mod)
app.register_blueprint(crud.mod)
general.py
from flask import Blueprint, render_template, session, redirect, url_for, \
request, flash, g, Response, jsonify
from flaskext.principal import Identity, Principal, RoleNeed, UserNeed, \
Permission, identity_changed, identity_loaded
from .. import principals
mod = Blueprint('general', __name__)
normal_role = RoleNeed('normal')
normal_permission = Permission(normal_role)
#mod.route('/')
#normal_permission.require(http_exception=403)
def index():
return "YOU'RE IN"
crud.py
from flask import Blueprint, render_template, session, redirect, url_for, \
request, flash, g, Response, jsonify, abort, Response
from mongokit import Connection, Document
from db import user_exists, email_exists, return_attribute, check_credentials
from forms import RegistrationForm, LoginForm
from .. import app
from flaskext.principal import Identity, Principal, RoleNeed, UserNeed, \
Permission, identity_changed, identity_loaded
from general import normal_role, normal_permission
mod = Blueprint('crud', __name__)
#mod.route('/login/', methods=['GET', 'POST'])
def login():
form = LoginForm(request.form)
error = None
if request.method == 'POST' and form.validate():
if check_credentials(form.username.data,form.password.data):
identity = Identity(form.username.data)
identity_changed.send(app, identity=identity)
return redirect(session['redirected_from'])
else:
return abort(401)
return render_template('login.html', form=form, error=error)
#app.route("/logout/")
def logout():
for key in ['identity.name', 'identity.auth_type', 'redirected_from']:
try:
del session[key]
except:
pass
return Response('<p>Logged out</p>')
#identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):
identity.provides.add(normal_role)
Thing is, I seem to be importing a lot of stuff into a lot of stuff. Right now it works. if i go to the index paged, which is handled by general.py blueprint and secured with normal_permission it redirects to /login which is handled by crud.py blueprint and if logged in redirects to index. Again, right now it... works but .. it also feels realllllllllly dirty and unclean and .. bleac... so unlike some of the good code I read :)
Any suggestions are welcome please. If this is not the way to tackle it, I'm willing to learn. I dont want to have some code that .. just works.
Thank you for your time reading this and maybe answering it.
ps. if i pasted too much code here let me know and I'll edit it out.
To access the current application from your blueprint's views, you should use the flask.current_app object, it is a proxy to the current application (and it's what's used in flask extensions for example).
Regarding your code, except the unused imports, it's well organised in my opinion, but i can't tell about the principal part, as i've never used it.