DiMarzio
DiMarzio

Reputation: 153

web2py: Using db(...) in a module

My controller file is getting pretty huge so I've decided to start splitting it up to smaller methods and take the methods to multiple module files. First thing, is this clever? Is this the pythonic/web2py way?

Anyway, I create my first module file my_module.py in the Modules section (where there is __init__.py already). I define a method my_method() in the module. I import the module in my controller: import my_module and call the method in the controller: my_module.my_method()

controller:

import my_module

...

def my_page():
    ...
    my_module.my_method()
    ...

module:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
from gluon import *

def my_method():
    ...
    rows = db(db.my_table.my_field == x).select()
    ...

However, now it gives me error:

File "/home/my_user/web2py/applications/my_app/controllers/default.py", line 568, in my_page

my_module.my_method()

File "applications/my_app/modules/my_module.py", line 10, in my_method

rows = db(db.my_table.my_field == x).select()

NameError: global name 'db' is not defined

I'm doing pretty basic db stuff and the method worked fine when it was defined in the controller itself. But why does the module work differently to the controller? Are there any other differences or caveats? Is using modules even worth it?

Upvotes: 2

Views: 1137

Answers (1)

Anthony
Anthony

Reputation: 25536

web2py executes model, controller, and view files in a prepared environment (which is created fresh on each HTTP request). Objects defined in model files (including the db object) are added to this environment and therefore available globally within any controller or view. However, modules imported into controllers work the same as any other Python module -- they are not executed in the web2py environment, and therefore, objects in the web2py environment are not globally available within imported modules.

In this case, you have a couple options. First, you could simply pass the db object to the function as an argument:

In the module:

def my_method(db):

In the controller:

my_module.my_method(db)

Alternatively, you could add the db object to the current object and import current into the module (as documented here):

In a model:

from gluon import current
current.db = db

In your module:

from gluon import current

def my_method():
    db = current.db # Keep this inside the function, not at the top level of the module.

Finally, note that you can also access any objects in the web2py environment via the current.globalenv dictionary, so rather than explicitly adding db to current, you could simple access it via current.globalenv['db'].

Upvotes: 2

Related Questions