Sharing objects between view and application with Pyramid

340 views Asked by At

I'm trying to create a web interface for a data analysis pipeline using Pyramid. I'm using deform and colander to make the forms. I've been adapting this example:

http://pyramid-tutorials.readthedocs.org/en/latest/humans/security/step02/

Most of the work gets done when a form gets submitted, but there are a couple of generic steps that only need to run once. Can I load some things into memory when the server starts up so that they are accessible from within a view?

2

There are 2 answers

3
pankaj28843 On BEST ANSWER

You can define some module level variables in the main file of your application (or may be somewhere else) and then use them by importing them as per your requirement.

I use this method to create settings like database connection string for SQLAlchemy from environment variables.

By default, a module will be parsed only once in Python, so you module level code will run only once.

Update 1

Let's assume directory structure of a pyramid project looks like this:

.
├── __init__.py
├── models
│   ├── __init__.py
│   ├── meta
│   │   ├── base.py
│   │   ├── __init__.py
│   │   ├── orm.py
│   │   ├── schema.py
│   │   ├── types.py
│   ├── users.py
├── security.py
├── settings
│   ├── database.py
│   ├── email.py
│   ├── __init__.py
│   ├── redis.py
│   ├── security.py
├── static
│   ├── css
│   │   └── main.css
│   └── js
│       ├── app.js
│       ├── app-services.js
│       ├── controllers
│       │   └── excel_preview.js
├── templates
│   ├── auth
│   │   └── login.html
│   ├── base.html
│   ├── home.html
├── views
│   ├── auth.py
│   ├── home.py
│   ├── __init__.py

Let's say we've following code in settings/redis.py:

import os
import redis


def get_redis_client():
    # Read settings from environment variables
    redis_db_name = os.environ.get('REDIS_NAME')
    redis_host = os.environ.get('REDIS_HOST')
    redis_port = os.environ['REDIS_PORT']

    # create a redis connection
    redis_client = redis.StrictRedis(
        host=redis_host,
        port=redis_port,
        db=redis_db_name,
    )

    # return newly created redis connection
    return redis_client


redis_client = get_redis_client()

SOME_SETTING_STORED_IN_REDIS = redis_client.get('some_setting_stored_in_redis')

You can use this SOME_SETTING_STORED_IN_REDIS variable from anywhere. If name of your app is example_app then in example_app/views/home.py you can use it like this:

from pyramid.view import view_config

from example_app.settings.redis import SOME_SETTING_STORED_IN_REDIS


def includeme(config):
    config.add_route('home', '/')


@view_config(
    route_name='home',
    renderer='home.html',
    permission='authenticated'
)
def home_view(request):

    return {
        "some_setting": SOME_SETTING_STORED_IN_REDIS,
    }

I think you're trying to achieve something similar.

1
Sergey On

If by "things which only need to run once" you mean something like a database connection, some configuration data etc. - in other words something which never changes during the lifecycle of the process then defining them as globals and re-using across the application is fine. Example:

APP_TITLE = 'Data Analysis Pipeline using Pyramid'

@view_config(...)
def home_view(request):
    return "Welcome to %s" % APP_TITLE

If you're thinking about storing some global state and re-using it across the views then it would not be a good idea. Example (bad, do not do this):

subscription_step = 1

@view_config(...)
def next_subscription_step(request):
    global subscription_step
    subscription_step += 1 
    return HTTPFound('/subscription/step_%s' % subscription_step)

The above code may appear to work for you locally, but things will start fall apart as soon as there's more than one user accessing the app, or if the webserver spawns another worker process, or if the webserver restarts, or a million of other reasons.