On Jun 8, 6:27 am, eddie <[email protected]> wrote:
> I've been considering some issues related to this. Where do people
> tend to locate their functions they are calling from controllers?

You can locate controller specific functions in your controller file;

>
> Obviously the simplest place is as a function defined in the same
> controller python file as where it is called from. But some down sides
> to this are:

You can also put "utility" functions in your models folder (which is
read in entirety per request);
You can then name them per file, logically.

The downside - they get read on each request (needed or not) - it's
convenient, but at some
point, not what you want to keep doing - then put them in a modules
folder, and - in the areas that
need them, let that be where you local_import() them, for calling.

That is pretty much the strategy chain, I think.

>
> * You end up with a handful of very large files in the controllers
> folder

--- yeah, don't do that (and particularly, don't let that situation
sneak up on you!)

> * Those functions can be potentially called as a URL via web2py

Functions that take a parameter are not exposed to external url's, or
which are named with a (by Python convention)  "private" name, i.e.
start with double-underscore.
In other words, you can always control this (when you choose to leave
something small in your controller area).

You can always add a parameter to a function which you just don't use,
if you don't like calling functions  like __foo().

>
> Maybe an example might clarify. Say you want to combine data from a
> couple of tables from the DB. You might need to do this in a few
> places in your controllers. You get back a list of some items, that
> are going to be displayed as a table.
>
> If the helper function is *purely* data driven, maybe you place it in
> the models folder. The function is then put in the global namespace,
> and can be called from any controller (I think, is that correct?)

Yes.   Also, that helper has access to global data (e.g. db.mytable).
You can also put it in models, and only import from controllers (or
even functions).

>
> More likely, the helper function might grab some data, and get it in
> to a form that will be easy to display in a view. For example, if you
> have a view layout with three columns, you might have all your
> controllers return 3 bits of content for each column, and so need to
> call 3 helper functions, one for each column's content that will be
> displayed.
>
> Now in this case, the modules folder can be useful for some cases, but
> you need ot pass items that are normally in the global namespace, for
> example the db. You also need to import the gluon modules.

think about making things modular, not making everything global....
look at existing plugins for example.

>
> So in summary, I can see a range of places to put these sort of
> functions, but they all seem to have a down side:
>
> * Models folder - Probably only appropriate if they are pure data
> manipulation

... or widely used utilities...

> * Modules folder - Great for functional code that is highly decoupled,
> but you need to pass items like the db that are normally in the
> controllers global namespace

... a good thing....  and should make you question how much they
should need to know, i.e. help guide you to less coupling...


> * Down the bottom of an existing controller file - Easiest approach,
> but your controller files quickly fill up with helper code. Doesn't
> really hide complexity. Extra controller functions can be called if
> someone enters the right URL

.... for lightweight, local to a logical controller file this is
prefectly ok, and you can control URL access.

> * In helper files in the controllers folder - Better than down the
> bottom of an existing controller file, but I can't get these files to
> be imported in other controllers, and these functions could still be
> called via the right URL
>
> What are people's solutions to making their controller code more
> modular?
>
> On Jun 5, 3:40 am, Thadeus Burgess <[email protected]> wrote:
>
> > All functions defined in models are available to controllers and views
> > as anything you put in the models becomes part of the global namespace
> > that the controllers/views are executed in.
>
> > This leads to potential problems of namespace collision.
>
> > Make sure you do not overwrite the function elsewhere, as this could
> > be causing issues.
>
> > Why are you calling db.create_object? This isn't a class of the DAL,
> > refer to Yarko's explanation, the DAL is not an ORM.
>
> > You probably mean.
>
> >   if form.accepts(request.vars, session):
> >        foo = create_object(owner_id=auth.auth_id, # NOT
> > db.create_object, just call your function like regular
> > template_name=form.vars.template)
>
> > --
> > Thadeus
>
> > On Fri, Jun 4, 2010 at 11:39 AM, Doug Warren <[email protected]> wrote:
> > > On Fri, Jun 4, 2010 at 9:11 AM, Yarko Tymciurak
> > > <[email protected]> wrote:
>
> > >> On Jun 4, 10:58 am, Doug Warren <[email protected]> wrote:
> > >>> I don't believe I want to local_import my db.py file as it's already
> > >>> set up by the environment correct?
>
> > >> Correct - you do not want / need to import your db.py.
>
> > >> As long as it is in your modelsfolder(by default it is), it's
> > >> already in your request context before your controller is called.
>
> > > Yes but as I mentioned in my original E-Mail, I was unable to get a
> > > function defined in the model file to be visible to the controller
> > > hence the original question. :)
>
> > > I thought about it a bit during my drive and think I will try (using
> > > the below example) something like:
> > > def create_object...
> > > ...
>
> > > co = create_object
>
> > > controller.py
> > >  co( template_id ...)
>
> > >>> What I'm asking for is a way to keep all of the code that relates to
> > >>> the model in one place and to invoke it from controllers.  That is if
> > >>> I define 5 tables for the model I'd expect to write helper functions
> > >>> to manipulate all 5 tables and not to have the controller know the
> > >>> intimate details of the model.  That's the concept behind Object
> > >>> Orientated programming isn't it?  Objects are black boxes to other
> > >>> objects other than their public facing interface.
>
> > >> Right - but DAL is just a Data abstraction layer (i.e. an SQL adapter,
> > >> if you will), not an ORM (i.e. there's not the level of object-
> > >> oriented abstraction that you would expect w/ an orm - it's lower
> > >> level)
>
> > >> So in web2py, with DAL you have knowledge of your table layout
> > >> (without direct knowledge / need for the specific back ends SQL).
>
> > >> You'll also find that forms, and validators are coupled to table
> > >> structure, so if / as you try to abstract away from table definitions,
> > >> you will run into this.
>
> > >> I'm sure others will add more comments...
>
> > >>> On Fri, Jun 4, 2010 at 8:56 AM, Yarko Tymciurak
>
> > >>> <[email protected]> wrote:
>
> > >>> > On Jun 4, 10:43 am, Doug Warren <[email protected]> wrote:
> > >>> >> Traditionally when I've written MVC style applications, the model
> > >>> >> would contain not only the data representing the objects but also the
> > >>> >> data for manipulating the objects.  I'm not sure how that same
> > >>> >> relation applies to web2py.
>
> > >>> >> If I have a model that defines 4-5 tables, 2 of them are just foreign
> > >>> >> key lookups, and creating a new object involves inserting data into 3
> > >>> >> of the tables, it seems that I would want a create_object method in 
> > >>> >> my
> > >>> >> model file.
>
> > >>> >> So I write something like:
>
> > >>> >> def create_object(owner_id=None, template=None):
> > >>> >>     # Some sanity checking on the above
> > >>> >>     new_object = db.objects.insert(template_id=template.id, 
> > >>> >> person_id=owner_id)
>
> > >>> >>     widgets = 
> > >>> >> db.template_widget(db.template_widget.thingy_template_id
> > >>> >> == template.id).select()
> > >>> >>     for widget in widgets: db.thingy_widget.insert(widget_id =
> > >>> >> widget.id, thingy_id = new_object)
>
> > >>> >>     whatchymacallits =
> > >>> >> db.template_whatchymacallit(db.template_whatchymacallit.thingy_template_id
> > >>> >> == template.id).select()
> > >>> >>     for whatchymacallit in whatchymacallits:
> > >>> >> db.thingy_whatchymacallit.insert(whatchymacallit_id =
> > >>> >> whatchymacallit.id, thingy_id = new_object)
>
> > >>> >>     return new_object
>
> > >>> >> and place that into my db.py.  Now the controller has a function 
> > >>> >> like:
> > >>> >> def create():
> > >>> >>     form = SQLFORM.factory( Field('template',
> > >>> >> requires=IS_IN_SET(__get_templates())))
> > >>> >>     if form.accepts(request.vars, session):
> > >>> >>         foo = db.create_object(owner_id=auth.auth_id,
> > >>> >> template_name=form.vars.template)
> > >>> >>         response.flash = "Created"
> > >>> >>     elif form.errors:
> > >>> >>         response.flash = "Error (hacker)"
>
> > >>> >> Well db is referring to the DAL db not the db.py, from db import
> > >>> >> create_object gives a name not found error, so I'm at a loss as to 
> > >>> >> how
> > >>> >> to define functions that work upon the model and can be invoked from
> > >>> >> one or more controllers.
>
> > >>> > I'm not sure what exactly you are saying here - but to import, use
> > >>> > local_import()
> > >>> > (seehttp://www.web2py.com/book/default/section/4/18?search=local_import)
>
> > >>> > BUT before you do, here is some background:
>
> > >>> > When a request comes into web2py,   here's what happens (roughly):
>
> > >>> > web2py parses the request url, and sets up an environment to call the
> > >>> > appropriate application / controller / function;
> > >>> > Part of that setup involves running all the files in your app's  model
> > >>> >folder(so that db connections, table definitions, etc. are all "there
> > >>> > for you");
>
> > >>> > This means you can put your files in the modelsfolder, and they will
> > >>> > be run (defined) before the call to your controller.
>
> > >>> > Then, your controller / function is called.
>
> > >>> > local_import will pull in definitions /modulesfrom your
> > >>> > application'smodulesfolder, but you can (for development certainly)
> > >>> > just put your file in your modelsfolder.
> > >>> > When you really want to reduce what gets run at _each_ request, you
> > >>> > might want to look at what to move tomodules, so that you're only
> > >>> > pulling in those files when needed.
>
> > >>> > As for db - DAL:   db is the "global" and "default"  name for the db
> > >>> > connection string (it is so named and setup in the default models/
> > >>> > db.py file).   You can change the name of this variable as you like
> > >>> > (or change your imports).
>
> > >>> > Hope this at least helps point you out of the forrest.
>
> > >>> > Regards,
> > >>> > - Yarko
> > >>> >> Are there any non-trivial example
> > >>> >> applications for web2py?  Most of the ones that I have seen assumes
> > >>> >> that all data you need in thedatabasecan be supplied from a form and
> > >>> >> that's not the case I run into over and over again.

Reply via email to