Search code examples
pythonpyramidpylons

How to put sessions on all pages without putting the session code on all views in pyramid?


I think my problem is related on the way I structured my pyramid project. What I want to accomplish is to make my code runs on all views, I don't want to paste same codes on all views. Its like I will include the code in all views by just simply calling it. This is my code.

my wizard module

from pyramid.view import view_config, view_defaults
from .models import *
from datetime import datetime
from pyramid.response import Response
from bson import ObjectId
from pyramid.httpexceptions import HTTPFound
import json

class WizardView:

def __init__(self, request):
    self.request = request

@view_config(route_name='wizard', renderer='templates/wizard.jinja2')
def wizard(self):
    session = self.request.session
    if session:
        return {'fullname':session['name'],'userrole':session['userrole']}
    else:
        url = self.request.route_url('login')
        return HTTPFound(location=url)

my bill module

from pyramid.view import view_config, view_defaults
from .models import *
from datetime import datetime
from pyramid.response import Response
from bson import ObjectId 
from pyramid.httpexceptions import HTTPFound

class BillView:

def __init__(self, request):
    self.request = request

@view_config(route_name='bills', renderer='templates/bills.jinja2')
def bills(self):
    session = self.request.session
    if session:
        return {'fullname':session['name'],'userrole':session['userrole']}
    else:
        url = self.request.route_url('login')
        return HTTPFound(location=url)

As you can see I have to paste this code twice (this code checks if session exist, if not, then redirect user to login page)

session = self.request.session
if session:
    return {'fullname':session['name'],'userrole':session['userrole']}
else:
    url = self.request.route_url('login')
    return HTTPFound(location=url)

I've tried to search and I think what I need is some sort of auto loader? How can I apply this on pyramid? Or should I stick with this process?


Solution

  • If you wish to return exactly the same thing from both (many) views, then the best way is to use inheritance.

    class GenericView:
        def __init__(self, request):
        self.request = request
    
        def generic_response(self):
            session = self.request.session
            if session:
                return {'fullname':session['name'],'userrole':session['userrole']}
            else:
                url = self.request.route_url('login')
                return HTTPFound(location=url)
    

    Use generic_response in WizardView and BillView

    class WizardView(GenericView):
    
        def __init__(self, request):
            super().__init__(request)
            # Do wizard specific initialization
    
        @view_config(route_name='wizard', renderer='templates/wizard.jinja2')
        def wizard(self):
            return self.generic_response()
    
    class BillView(GenericView):
    
        def __init__(self, request):
            super().__init__(request)
            # Do bill specific initialization
    
        @view_config(route_name='bills', renderer='templates/bills.jinja2')
        def bills(self):
            return self.generic_response()
    

    If you want to just check (and redirect) when session does not exists and otherwise proceed normally you could use custom exceptions and corresponding views.

    First define custom exception

    class SessionNotPresent(Exception):
        pass
    

    And view for this exception

    @view_config(context=SessionNotPresent)
    def handle_no_session(context, request):
         # context is our custom exception, request is normal request
         request.route_url('login')
         return HTTPFound(location=url)
    

    Then just check if session exists in parent constructor

    class SessionView:
        def __init__(self, request):
            self.request = request
            if not self.request.session:
                raise SessionNotPresent() # Pyramid will delegate request handilng to handle_no_request
    

    In views simply extend SessionView and non existing sessions will be handeled by handle_no_session.

    class WizardView(SessionView):
    
        def __init__(self, request):
            super().__init__(request)
            # Do wizard specific initialization
    
        @view_config(route_name='wizard', renderer='templates/wizard.jinja2')
        def wizard(self):
            session = self.request.session
            return {'fullname':session['name'],'userrole':session['userrole']}
    
    
    class BillView(SessionView):
    
        def __init__(self, request):
            super().__init__(request)
            # Do bill specific initialization
    
        @view_config(route_name='bills', renderer='templates/bills.jinja2')
        def bills(self):
            session = self.request.session
            return {'fullname':session['name'],'userrole':session['userrole']}
    

    You could easily add additional parameters to exception (redirect_url, ...)

    For exception handling see http://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/pylons/exceptions.html