On all my template rendering for a particular app, the output ends with None:
...</html>None
This must be a bug and probably in my code and I've spent days trying to track it down. There's nothing special about my app and this bug appears on every page I use template rendering, whether I use a seperate template engine or not. There is nothing special about my code:
class Objectives(NewBaseHandler):
#user_required
def get(self):
user = auth_models.User.get_by_id(long(self.auth.get_user_by_session()['user_id']))
if user:
self.render_template('objectives.html', {'user': user})
else:
self.render_template('/', {})
class NewBaseHandler(BaseHandler):
"""
........BaseHandler for all requests
........Holds the auth and session properties so they are reachable for all requests
...."""
def dispatch(self):
"""
............Save the sessions for preservation across requests
........"""
# self.session_store = sessions.get_store(request=self.request)
# if self.request.host.find('localhost') > 0: # for a Swedish domain that uses Swedish
# or lang = os.environ.get("HTTP_ACCEPT_LANGUAGE")
i18n.get_i18n().set_locale('sv')
lang_code_get = self.request.get('hl', None)
if lang_code_get:
#self.session['i18n_language'] = lang_code_get
i18n.get_i18n().set_locale(lang_code_get)
try:
response = super(NewBaseHandler, self).dispatch()
self.response.write(response)
finally:
self.session_store.save_sessions(self.response)
#webapp2.cached_property
def auth(self):
return auth.get_auth()
#webapp2.cached_property
def session_store(self):
return sessions.get_store(request=self.request)
#webapp2.cached_property
def auth_config(self):
"""
............Dict to hold urls for login/logout
........"""
return {'login_url': self.uri_for('login'),
'logout_url': self.uri_for('logout')}
class BaseHandler(webapp2.RequestHandler):
#webapp2.cached_property
def jinja2(self):
return jinja2.get_jinja2(app=self.app)
def render_template(self, file, template_args):
path = os.path.join(os.path.dirname(__file__), 'templates',
file)
self.response.out.write(template.render(path, template_args))
def render_jinja(self, filename, **template_args):
self.response.write(self.jinja2.render_template(filename,
**template_args))
How can I check where the output None is coming from? It's probably not coming from the template and it doesn't seem to be coming from the handlers and there is no other code.
Thank you
In Objectives.get() you must return a value. Since you don't do this Python assumes the result is None. This value you get in NewBaseHandler.dispatch() when calling to base dispatch implementation and then write it to response.
If I get your app correctly returning empty string in get method will solve the problem.
Related
I have a middleware in my app that sets the currently logged in user. On my local machine, get_current_user() works fine, but it seems to return None when the app is run in a kubernetes container. What am I missing?:
USER_ATTR_NAME = getattr(settings, "LOCAL_USER_ATTR_NAME", "_current_user")
_thread_locals = local()
def _do_set_current_user(user_fun):
setattr(_thread_locals, USER_ATTR_NAME, user_fun.__get__(user_fun, local))
def _set_current_user(user=None):
"""
Sets current user in local thread.
Can be used as a hook e.g. for shell jobs (when request object is not
available).
"""
_do_set_current_user(lambda self: user)
class SelfServeCurrentUserMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# request.user closure; asserts laziness;
# memorization is implemented in
# request.user (non-data descriptor)
_do_set_current_user(lambda self: getattr(request, "user", None))
response = self.get_response(request)
return response
def get_current_user():
current_user = getattr(_thread_locals, USER_ATTR_NAME, None)
if callable(current_user):
return current_user()
return current_user
def get_current_authenticated_user():
current_user = get_current_user()
if isinstance(current_user, AnonymousUser):
return None
return current_user
all what you do shows me - you don't really understand, how Django works.
What i mean:
You need User model, somewhere, probably it is form. You don't understand, how to get a user there, and you try to use locals. You made a import of functions get_current_user, get_current_authenticated_user. Now you can achieve a User. This is wrong for Django, but you can do it.
i have a small trick for you in this case:
from django.utils.translation.trans_real import _active as _thread_locals
# _thread_locals = local() you don't need it.
... # other staff
this is what you want. See the commentary about _active in django code
I'm trying to create a website with optional url sub-paths:
/user - Returns general information on users
/user/edit - Edits the user
I've tried setting:
config.add_route('user', '/user/{action}')
#view_defaults(route_name="user")
class UserViews():
# not sure what (if anything) to put in #view_config here...
def user_general(self):
return Response("General User Info"
#view_config(match_param="action=edit")
def edit(self):
return Response("Editing user")
However while this works for /user/edit, it returns a 404 for /user
It also fails in the same way if I set 2 explicit routes with a shared path - e.g.:
config.add_route('login', '/user')
config.add_route('edit_user', '/user/edit')
I've tried things like setting match_params="action=" but can't get it to work.
Any ideas on how this can be achieved?
user_general inherits the default route configuration of the class, which requires an {action} match param. When you do not supply that in the request, the route for that view will never match, returning a 404 not found response.
You need to add a decorator with the route_name argument to user_general to override the default route for the view.
#view_config(
route_name="user"
)
def user_general(self):
The following works for me as a complete example with some minor explicit naming conventions.
from wsgiref.simple_server import make_server
from pyramid.config import Configurator
from pyramid.response import Response
from pyramid.view import view_config, view_defaults
#view_defaults(route_name="user_action")
class UserViews():
def __init__(self, context, request):
self.request = request
self.context = context
#view_config(
route_name="user_get",
request_method="GET"
)
def get_user(request):
return Response("I got you, Babe!")
#view_config(
match_param="action=edit"
)
def edit(self):
return Response("Don't ever change, Babe!")
if __name__ == "__main__":
with Configurator() as config:
config.add_route("user_get", "/user")
config.add_route('user_action', '/user/{action}')
config.scan()
app = config.make_wsgi_app()
server = make_server("0.0.0.0", 6543, app)
server.serve_forever()
I've been moving from bottle to flask. I'm the type of person that prefers writing my own code instead of downloading packages from the internet if I the code needed is 20 lines or less. Take for example support for Basic authentication protocol. In bottle I could write:
def allow_anonymous():
"""assign a _allow_anonymous flag to functions not requiring authentication"""
def wrapper(fn):
fn._allow_anonymous = True
return fn
return wrapper
def auth_middleware(fn):
"""perform authentication (pre-req)"""
def wrapper(*a, **ka):
# if the allow_anonymous annotation is set then bypass this auth
if hasattr(fn, '_allow_anonymous') and fn._allow_anonymous:
return fn(*a, **ka)
user, password = request.auth or (None, None)
if user is None or not check(user, password):
err = HTTPError(401, text)
err.add_header('WWW-Authenticate', 'Basic realm="%s"' % realm)
return err
return fn(*a, **ka)
return wrapper
...
app = Bottle()
app.install(middleware.auth_middleware)
The above code gave me full support for basic auth protocol for all methods unless explicitly decorated with the #allow_anonymous wrapper. I'm just a beginner with flask. I'm having a hard time accomplishing the bottle-compatible code above in flask without adding dependencies on more python packages or excessive boiler-plate. How is this handled directly and clearly in flask?
You can definitely some of the functionality of flask-httpauth yourself, if you wish :-P
I would think you will need to play some before_request games (not very beautiful), or alternatively call flask's add_url_rule with a decorated method for each api endpoint (or have a route decorator of your own that will do this). The add_url_rule gets a view function that is usually your api endpoint handler, but in your case, will be a wrapped method in a manner very much like the one you gave in the post (auth_middleware).
The gist of it:
from flask import Flask, make_response, request
app = Flask(__name__)
def view_wrapper(fn):
"""
Create a wrapped view function that checks user authorization
"""
def protected_view(*a, **ka):
# if the allow_anonymous annotation is set then bypass this auth
if hasattr(fn, '_allow_anonymous') and fn._allow_anonymous:
return fn(*a, **ka)
# consult werkzeug's authorization mixin
user, password = (request.authorization.username, request.authorization.password) if request.authorization else (None, None)
if user is None or not check(user, password):
err_response = make_response(text, 401)
err_response.headers['WWW-Authenticate'] = 'Basic realm="%s"' % realm
return err_response
return fn(*a, **ka)
return protected_view
# An endpoint
def hello():
return 'hello there'
app.add_url_rule('/', 'hello', view_wrapper(hello))
Of course, this can (and should) be further enhanced with Blueprints, etc.
Note #1: this is cribbed from separate answers in SO.
Note #2: this doesnt use blueprints. Again, I'm new to flask and I appreciate that blueprints will help the app scale but one step at a time...
def allow_anonymous(decorated_function):
decorated_function.is_public = True
return decorated_function
#app.before_request
def auth_middleware():
fn = app.view_functions[request.endpoint]
if hasattr(fn, 'allow_anonymous') and fn.allow_anonymous:
# anonymous permitted
return
elif my_custom_authentication():
# anonymous not permitted authentication succeeded
return
else:
# anonymous not permitted authentication failed
err_response = make_response(text, 401)
err_response.headers['WWW-Authenticate'] = 'Basic realm="%s"' % realm
return err_response
#app.route('/public_thing')
#allow_anonymous
def public_thing():
return 'yo'
#app.route('/regular_thing')
def regular_thing():
return 'if you can read this youre authenticated.'
I want to build a simple webapp as part of my learning activity. Webapp is supposed to ask for user to input their email_id if it encounters a first time visitor else it remembers the user through cookie and automatically logs him/her in to carry out the functions.
This is my first time with creating a user based web app. I have a blue print in my mind but I am unable to figure out how to implement it. Primarily I am confused with respect to the way of collecting user cookie. I have looked into various tutorials and flask_login but I think what I want to implement is much simpler as compared to what flask_login is implementing.
I also tried using flask.session but it was a bit difficult to understand and I ended up with a flawed implementation.
Here is what I have so far (it is rudimentary and meant to communicate my use case):
from flask import render_template, request, redirect, url_for
#app.route("/", methods= ["GET"])
def first_page():
cookie = response.headers['cookie']
if database.lookup(cookie):
user = database.get(cookie) # it returns user_email related to that cookie id
else:
return redirect_url(url_for('login'))
data = generateSomeData() # some function
return redirect(url_for('do_that'), user_id, data, stats)
#app.route('/do_that', methods =['GET'])
def do_that(user_id):
return render_template('interface.html', user_id, stats,data) # it uses Jinja template
#app.route('/submit', methods =["GET"])
def submit():
# i want to get all the information here
user_id = request.form['user_id']# some data
answer = request.form['answer'] # some response to be recorded
data = request.form['data'] # same data that I passed in do_that to keep
database.update(data,answer,user_id)
return redirect(url_for('/do_that'))
#app.route('/login', methods=['GET'])
def login():
return render_template('login.html')
#app.route('/loggedIn', methods =['GET'])
def loggedIn():
cookie = response.headers['cookie']
user_email = response.form['user_email']
database.insert(cookie, user_email)
return redirect(url_for('first_page'))
You can access request cookies through the request.cookies dictionary and set cookies by using either make_response or just storing the result of calling render_template in a variable and then calling set_cookie on the response object:
#app.route("/")
def home():
user_id = request.cookies.get('YourSessionCookie')
if user_id:
user = database.get(user_id)
if user:
# Success!
return render_template('welcome.html', user=user)
else:
return redirect(url_for('login'))
else:
return redirect(url_for('login'))
#app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
# You should really validate that these fields
# are provided, rather than displaying an ugly
# error message, but for the sake of a simple
# example we'll just assume they are provided
user_name = request.form["name"]
password = request.form["password"]
user = db.find_by_name_and_password(user_name, password)
if not user:
# Again, throwing an error is not a user-friendly
# way of handling this, but this is just an example
raise ValueError("Invalid username or password supplied")
# Note we don't *return* the response immediately
response = redirect(url_for("do_that"))
response.set_cookie('YourSessionCookie', user.id)
return response
#app.route("/do-that")
def do_that():
user_id = request.cookies.get('YourSessionCookie')
if user_id:
user = database.get(user_id)
if user:
# Success!
return render_template('do_that.html', user=user)
else:
return redirect(url_for('login'))
else:
return redirect(url_for('login'))
DRYing up the code
Now, you'll note there is a lot of boilerplate in the home and do_that methods, all related to login. You can avoid that by writing your own decorator (see What is a decorator if you want to learn more about them):
from functools import wraps
from flask import flash
def login_required(function_to_protect):
#wraps(function_to_protect)
def wrapper(*args, **kwargs):
user_id = request.cookies.get('YourSessionCookie')
if user_id:
user = database.get(user_id)
if user:
# Success!
return function_to_protect(*args, **kwargs)
else:
flash("Session exists, but user does not exist (anymore)")
return redirect(url_for('login'))
else:
flash("Please log in")
return redirect(url_for('login'))
return wrapper
Then your home and do_that methods get much shorter:
# Note that login_required needs to come before app.route
# Because decorators are applied from closest to furthest
# and we don't want to route and then check login status
#app.route("/")
#login_required
def home():
# For bonus points we *could* store the user
# in a thread-local so we don't have to hit
# the database again (and we get rid of *this* boilerplate too).
user = database.get(request.cookies['YourSessionCookie'])
return render_template('welcome.html', user=user)
#app.route("/do-that")
#login_required
def do_that():
user = database.get(request.cookies['YourSessionCookie'])
return render_template('welcome.html', user=user)
Using what's provided
If you don't need your cookie to have a particular name, I would recommend using flask.session as it already has a lot of niceties built into it (it's signed so it can't be tampered with, can be set to be HTTP only, etc.). That DRYs up our login_required decorator even more:
# You have to set the secret key for sessions to work
# Make sure you keep this secret
app.secret_key = 'something simple for now'
from flask import flash, session
def login_required(function_to_protect):
#wraps(function_to_protect)
def wrapper(*args, **kwargs):
user_id = session.get('user_id')
if user_id:
user = database.get(user_id)
if user:
# Success!
return function_to_protect(*args, **kwargs)
else:
flash("Session exists, but user does not exist (anymore)")
return redirect(url_for('login'))
else:
flash("Please log in")
return redirect(url_for('login'))
And then your individual methods can get the user via:
user = database.get(session['user_id'])
I've been trying out pyramid and this traversal thing is sending me nuts. I'm basically fiddling around to make a control panel for a shopping cart and this is the basic structure that I have in mind.
The login page
localhost:6543/admin_login
Upon successful login
localhost:6543/admin/home
To view all existing products
localhost:6543/admin/product
To edit product X
localhost:6543/admin/product/edit/1
So my folder structure is something like this ( Capitalize files are models )
mycart
resources.py
Admin.py
Product.py
static
templates
views
__init__.py
admin.py
root.py
My resources.py
from pyramid.security import Authenticated
from pyramid.security import Allow
from pyramid.response import Response
class Root(object):
__name__ = ''
__parent__ = None
def __init__(self, request):
pass
def __getitem__(self, key):
if key == 'admin_login':
return Admin()
elif key == 'admin':
return Admin()
raise KeyError
class Admin(object):
__name__ = ''
__parent__ = Root
__acl__ = [(Allow, Authenticated, 'admin')]
def __init__(self):
pass
In views/__init.py, it's simply a blank file.
As for root.py, it's simply a httpexceptions.HTTPNOTFOUND, 404 code
For views/admin.py
from pyramid.view import view_config, render_view
import mycart.resources
from pyramid.httpexceptions import HTTPNotFound, HTTPFound
from mycart.views.root import strip_tags
from pyramid_mailer import get_mailer
from pyramid_mailer.message import Message
from pyramid.security import remember , forget , authenticated_userid
from pyramid.events import subscriber , BeforeRender
from mycart.Admin import Admin
from mycart.Product import Product
#view_config(context='mycart:resources.Admin', request_method='POST', renderer='admin/login.jinja2')
def login_post(context, request):
if 'btnLogin' in request.params:
token = request.session.get_csrf_token()
login = request.params['txtLogin']
password = request.params['txtPassword']
admin = Admin(login, request)
if admin.validate_user( password):
record = admin.find_user_by_login( login )
request.session['bs_admin_id'] = str(record['_id'])
request.session['bs_admin_name'] = record['usr']['fname'] + ' ' + record['usr']['lname'];
request.session['bs_admin_type'] = record['usr']['type']
headers = remember(request, login )
return HTTPFound('/admin/home', headers=headers)
message = 'Failed login'
return {'message': message, 'url': '/admin_login', 'page_title': 'Failed Login'}
#view_config(context='mycart:resources.Admin', name="home", renderer='admin/home.jinja2', permission='admin')
def home(context, request):
logged_in = authenticated_userid(request)
url = request.path_info
admin = Admin( logged_in, request )
rec = admin.find_user_by_objectid( request.session['bs_admin_id'] ) ;
return { 'firstname': rec['usr']['fname'] }
#view_config(context='mycart:resources.Admin', name="product", renderer='admin/product_listing.jinja2', permission='admin')
def product_list(context, request):
print ('yes, showing product listing requested by ', request.session['bs_admin_id'] )
After logging in, I point the url to localhost:6543/admin/product, I notice that it still rendering the home page, instead of the product page.
I know I missed out something but I can't seem to find out why. Looking through http://docs.pylonsproject.org/projects/pyramid/en/1.3-branch/narr/traversal.html, I know that I on the right track as there might be arbitary segments.
I've tried modifying resources.py to be the following
.....
class Admin(object):
__name__ = ''
__parent__ = Root
__acl__ = [(Allow, Authenticated, 'admin')]
def __init__(self):
pass
def __getitem__(self, key):
if key == 'product':
print ("WOOT! Listing products")
## this is the part where I don't know what should I return or set or how should I hook it up with view_config
if key == 'home':
print ("yes, I'm home!")
## this is the part where I don't know what should I return or set or how should I hook it up with view_config
raise KeyError
For this part, I made some progress where it's definitely printing the respective message in the console. However , I have no inkling how should I hook it up with the view_configs and what should be parameters be for the view_configs if any changes need to be made.
I do not know if version affects anything but anyway, I am using python 3.3
Any help will be appreciated. Thanks!
This is my first time coding in python after years of java. So there might be some terms / concepts that I'm not familiar with respect to pyramid / python.
Ok, I think I kinda got my mind to wrap around this traversal thing. Reading through http://docs.pylonsproject.org/projects/pyramid/en/1.4-branch/narr/traversal.html, 2 things caught my attention.
For example, if the path info sequence is ['a', 'b', 'c']:
- Traversal starts by acquiring the root resource of the application by calling the root factory. The root factory can be configured to return whatever object is appropriate as the traversal root of your application.
- Next, the first element ('a') is popped from the path segment sequence and is used as a key to lookup the corresponding resource in the root. This invokes the root resource’s __getitem__ method using that value ('a') as an argument.
- If the root resource “contains” a resource with key 'a', its __getitem__ method will return it. The context temporarily becomes the “A” resource.
So based on localhost:6543/admin/products, the settings for view_config is like the following:
#view_config(context=Admin, name='products', .... )
So after making changes to resources.py
## class Root(object):
....
class ProductName(object):
def __init__(self, _key):
pass
class Products(object):
__name__ = ''
__parent__ = Root
def __init__(self):
pass
def __getitem__(self, key):
print ('products: ', key)
if key == 'add':
return ProductName(key)
print ('Approaching KeyError')
raise KeyError
class Admin(object):
__name__ = ''
__parent__ = Root
__acl__ = [(Allow, Authenticated, 'admin')]
def __init__(self):
pass
def __getitem__(self, key):
if key == 'products':
print ('admin: ', key)
return Products()
raise KeyError
And in views/admin.py
#view_config(context=Admin, name='products', renderer='admin/products.jinja2', permission = 'admin')
def product_add(context, request):
print 'hey products_add'
return { 'msg': ''}
Somehow or rather, it isn't rendering the product template, but the default 404.
You take a look at the doc about traversal, because you've haven't got it quite right. This tutorial is also quite useful in understanding traversal. I'll try to do a quick explanation in your context :
First of all, the path of the request is split intro segments. For example /admin/product is split into ['admin', 'product'].
Then, pyramid tries to determine the context for this request. For that, it recursively call __getitem__ (which is just another way to say it does object[segment]) for each segment from the root (it traverses). In the exemple, it does root['admin'], which returns an admin object, then does admin['product']. It stops when it encounters a KeyError.
Once we have a context, pyramid searches for a view with this context, and whose view name is the part that wasn't traversed. For example, if admin['product'] raise a KeyError, then pyramid looks for a view that configured with #view_config(context=Admin, name="product").
So, how do you make an app from that ? First, you determine what is your resource tree. In your case, it might looks like this :
Root
Admin
ProductContainer
Product
There is a view named home for the Admin context (/admin/home), a view with no name for the ProductContainer (/admin/product) and a view named edit for the product (/admin/product/1/edit).
While I do not know if the code below is elegant or any loopholes, it is definitely working for me now. I'll put it in , in case someone is facing the same problem like me.
resources.py
class ProductName(object):
__name__ = ''
__parent__ = Root
__acl__ = [(Allow, Authenticated, 'admin')]
def __init__(self, _key):
pass
class Products(object):
__name__ = ''
__parent__ = Root
__acl__ = [(Allow, Authenticated, 'admin')]
def __init__(self):
pass
def __getitem__(self, key):
print ('products: ' + key)
if key == 'add':
return ProductName(key)
print ('Approaching KeyError')
raise KeyError
views/admin.py
#view_config(context="**mycart:resources.ProductName**", name="", renderer='admin/product_add.jinja2', permission = 'admin')
def product_add(context, request):
print 'hey product add'
return { 'msg': ''}
#view_config(context="**mycart:resources.Products**", name='' , renderer='admin/product.jinja2', permission = 'admin')
def product(context, request):
print 'hey products listing'
return { 'msg': ''}