Where should I put code shared by multiple controllers?

3 views
Skip to first unread message

johnnyice

unread,
Jul 2, 2008, 5:38:04 PM7/2/08
to pylons-discuss
I have code that accesses the model, but it shared by multiple
controllers. In CakePHP this would be a component (small piece of
code shared by controllers), but does that make sense in pylons?

If so i could just do:

from myappname.controllers.components import my_shared_code


What have others done?

Mike Orr

unread,
Jul 2, 2008, 6:10:32 PM7/2/08
to pylons-...@googlegroups.com

There's no official place, but good choices would be the base
controller, a subclass of the base controller, or a 'lib' module.

It partly depends on whether it has to access 'self' (in which case it
can't be a function), and whether it has to access
request/response/session/render (which some people may feel
uncomfortable putting in a function).

--
Mike Orr <slugg...@gmail.com>

Fernando Aramendi

unread,
Jul 2, 2008, 6:20:58 PM7/2/08
to pylons-...@googlegroups.com
what about reusing SQLAlchemy queries? do you put them as class methods in domain classes, repositories/daos, controllers?

johnnyice

unread,
Jul 2, 2008, 8:32:07 PM7/2/08
to pylons-discuss
it needs to take a few params from the calling controller. this
component itself doesn't need accesss to 'self', but it will need
access to the db/models. of course i would import that, but would it
break the MVC pattern if i were to access a model from a lib?
> Mike Orr <sluggos...@gmail.com>

Jonathan Vanasco

unread,
Jul 2, 2008, 10:44:10 PM7/2/08
to pylons-discuss
controller inheritance:

we do a mixture of:
- leave them in /controllers , but use _ as a prefix
- put them in /controllers/shared
- put them in /lib/controllers

model inheritance:

i'd create a few files named _helpers.py , _mixins.py , etc

if you have very standardized items, you can cheat a little -- do
stuff like:

class _helper_std():
def get_by_id( self , Session , id ):
return Session.query( self.__class__ ).filter_by( id = id )

class user( _helper_std ) :
pass

class group( _helper_std ) :
pass

user= model.user().get_by_id( Session , 10001 )
group= model.group().get_by_id( Session , 10001 )

Mike Orr

unread,
Jul 3, 2008, 12:31:30 AM7/3/08
to pylons-...@googlegroups.com
On Wed, Jul 2, 2008 at 3:20 PM, Fernando Aramendi <fara...@gmail.com> wrote:
> what about reusing SQLAlchemy queries? do you put them as class methods in
> domain classes, repositories/daos, controllers?

I make class method in my ORM classes for all the queries I need.
They return either a query or some higher-level value.

--
Mike Orr <slugg...@gmail.com>

Mike Orr

unread,
Jul 3, 2008, 12:45:58 AM7/3/08
to pylons-...@googlegroups.com
On Wed, Jul 2, 2008 at 5:32 PM, johnnyice <jjb...@gmail.com> wrote:
>
> it needs to take a few params from the calling controller. this
> component itself doesn't need accesss to 'self', but it will need
> access to the db/models. of course i would import that, but would it
> break the MVC pattern if i were to access a model from a lib?

There are differing opinions on that. My opinion is that the model
should not depend on anything else in Pylons, but anything else can
use the model. Although I try to avoid having the template look in
the model directly unless it's just a trivial constant.

My general rule is to import only the ORM classes, and to make class
methods for any queries needed or any non-ORM operations. The Session
is imported only for writes (.save(), .delete(), .commit()).

So when I needed a a semi-generic auth library that uses three tables,
I put the integrity-checking function in the model because it depends
on several custom queries. But the main auth code, which checks the
password and instantiates the User object containing the permissions,
is in a lib module.

--
Mike Orr <slugg...@gmail.com>

Charles Brandt

unread,
Jul 3, 2008, 7:55:15 AM7/3/08
to pylons-...@googlegroups.com
I'm trying to route /user to UserController, but instead of storing
UserController in user.py, I would like to store it in a file named
user_controller.py.

I've been looking at pylons.wsgiapp in the PylonsApp resolve and
find_controller methods, and also in the Routes package itself. Right
now the controller is only found using the full name of user_controller,
but then pylons appends an extra "Controller" to the end of the
generated controller name. I'm not sure when or where in the request
cycle would be the right time to update the controller's location.

Is there an easier way than updating core code? Has anyone else tackled
this before?

Thanks in advance!

Ben Bangert

unread,
Jul 3, 2008, 3:11:25 PM7/3/08
to pylons-...@googlegroups.com
On Jul 2, 2008, at 3:20 PM, Fernando Aramendi wrote:

> what about reusing SQLAlchemy queries? do you put them as class
> methods in domain classes, repositories/daos, controllers?

I always try and put all my domain logic (SA queries), as class
methods or instance methods on the SQLAlchemy domain classes. Makes it
much easier to fix queries for efficiency later where it'll kick in
site-wide, rather than tracking down queries all over the place.

- Ben

Poli García

unread,
Jul 3, 2008, 5:06:27 PM7/3/08
to pylons-...@googlegroups.com
Also doing that makes that logic testable... what do you think?

Poli García

Ross Vandegrift

unread,
Jul 4, 2008, 12:12:50 PM7/4/08
to pylons-...@googlegroups.com
On Wed, Jul 02, 2008 at 09:45:58PM -0700, Mike Orr wrote:
> So when I needed a a semi-generic auth library that uses three tables,
> I put the integrity-checking function in the model because it depends
> on several custom queries. But the main auth code, which checks the
> password and instantiates the User object containing the permissions,
> is in a lib module.

Just for an alternate perspective...

I've taken a rich-model approach. Since the model defines the objects
that the application uses, it's very natural to make the objects rich
by extending their business-logic functionality in the model.

In my version of the above, I'd have a User object that was capable of
doing something like:

try:
u = model.User(username, password)
except AuthFailure:
...


Higher-level business logic that combines many different pieces of
functionality from different model objects goes into the lib.

I've found one downside to putting more functionality inside the model
code. Suppose there are two classes, model.A and model.B. If A
refers to some piece of B, it's very easy to run into circular import
statements. Fixing that is a bit of a headache, but I've gotten
better at not doing that :)

--
Ross Vandegrift
ro...@kallisti.us

"The good Christian should beware of mathematicians, and all those who
make empty prophecies. The danger already exists that the mathematicians
have made a covenant with the devil to darken the spirit and to confine
man in the bonds of Hell."
--St. Augustine, De Genesi ad Litteram, Book II, xviii, 37

Reply all
Reply to author
Forward
0 new messages