On Thursday, February 16, 2017 at 6:39:37 AM UTC-8, Anthony wrote: > > In your example above, it's one model defining tables from another model. >> But in my case, what I have is a controller function that needs access to >> the db, which is defined in the model file. But I found the hard way (and >> later also from an old thread: >> https://groups.google.com/forum/#!topic/web2py-developers/5TPI9oYOZHM ) >> that exec_environment does not load models. So this puts me kind of back >> to where I was. >> >> The simplest solution I found was to put, in the controller file, code >> that looks like this: >> >> from applications.otherapp.modules.db_definer >> db = db_definer.define_db() >> >> Then every time my controller is run, it will redefine the DB, using the >> code set up in the other app's module to do this in a consistent way (along >> the lines you suggested). >> >> What I don't like about this is that it means the DB-setup code is run >> multiple times on a "normal" request. That is, if I have code to set up >> the DB in my model file, and I visit my db-accessing controller, it runs >> the code in the model file to set up the DB, then runs the code again when >> it runs the controller file. I imagine this is not a huge penalty but it >> is annoying. >> > > So, then don't do it that way. You have two options. First, if you have a > controller that doesn't need any of the model definitions from your > application's model files, then you should probably re-architect your > application so only the models that are needed get defined when they are > needed (either using the conditional models functionality or by defining > all models in modules that are imported where needed). >
Thanks for your quick reply. Not sure what you mean there about the models. What you describe is the opposite of my situation. My controller does need the models. That is exactly the problem, because I want to call that controller from another controller, but to do so I need the model files to be run. > The other option is simply to avoid re-running the DB setup code and > instead use the already defined db object, passing it to the module code > from the other app: > > app1/models/db.py: > > db = DAL(...) > > app2/modules/db_definer.py: > > def define_tables(db): > db.define_table('my_app2_table', ...) > > app1/controllers/default.py: > > from app2.modules.db_definer import define_tables > > def myfunc(): > define_tables(db) > ... > > The above assumes both apps are using the same database, but if they are > not, then there is no "re-running the DB setup code" anyway, as you would > be dealing with two different databases, which would each need their own > setup code. > > What already-defined DB object? If I use exec_environment, model files aren't run, so there is no db object. In fact both controllers are using the same models, but if I use exec_environment, the object I get doesn't know about any models. I could put code to create the models in the controller function (or in the controller top-level), which seems to be what your example is doing), but then I am, again, re-running that model-creation code twice (once in the original controller and once in the exec-ed controller). Incidentally, I tried to just inject the db object into the object I get from exec_environment, but even this is difficult. The reason is that exec_environment executes the file in a dict namespace, but then what it returns is not that dict, but a Storage object that is a (shallow) copy of it. So if I do "c = exec_environment('some/controller.py')", the object c is not in fact the global namespace of the execed file, but a copy of it. Normally I would be able to do "c.db = db" to inject db as a global variable, but instead I had to do tricky things like "c.some_function.func_globals['db'] = db". Anyway, your response makes me think maybe I haven't explained my situation correctly. What I have this: controllerA.py and controllerB both needs the model in modelA.py controllerB wants to call a function in controllerA. What I want is a way, from within controller B, to say "run controllerA, making sure all the models it needs are available to it, and then give me controllerA as a module object (or something equivalent), so that I can call controllerA.some_function() and get the results". All without any additional network requests. (In fact, some_function is a service, so I will pass arguments to it.). The problem is that I don't want these internal cross-app calls to be >> considered "requests"; I just want them to be calls to controller >> functions, so anything like requires_https should be ignored (or just >> proxied to the "real" request which is making this sub-call to another app). >> > > It should only take effect for HTTP requests, not executions via the > shell, scheduler, or cron. > > As I mentioned, the problem is that exec_environment does not run models, and gluon.shell.env creates a new "request" object which apparently does not preserve the HTTPS-ness of the original request. (And it also stomps on the "current" object.) So what I want is neither an HTTP request, nor an execution via the shell, scheduler or cron, but a direct execution of an "extra" controller, in a way that ensures the controller has access to all the models that it needs. > The upshot of all this appears to be that there is no real way to get >> web2py to give me access to the model/controller combination without an >> HTTP request. In web2py the models and controllers are tightly coupled to >> the HTTP request. I find this somewhat irritating, as to my mind in an MVC >> framework the models and controllers shouldn't be so closely tied to the >> transport mechanism. That is, I should be able to say "use this model and >> this controller and give me the data", without having to involve HTTP at >> all. It seems that, in web2py this coupling is encouraged because >> controller functions directly access objects like request and response to >> get their arguments, rather than having a separate "routing" mechanism that >> maps HTTP request parameters to Python functions. (This is what the >> "Service" function does, but it requires a level of indirection with a >> "call" entry point.) >> > >> > In essence, the way I think of it, when a request comes in, it is routed >> to a controller function. That controller then runs along with its >> associated models. and the controller function is called. It returns some >> data, which is passed to a view. What I would like is the ability to do >> just the middle part of that: take a controller, load its models, and run a >> function. No HTTP. No request. No response. No network. No view. No >> nothing. Just the controller and the model. For now I have a way to do >> it, but it involves duplicating the model-controller linkage that web2py >> already does (by "manually" recreating the DAL object from within the >> controller). >> > > If you need to share code across applications, I suggest you put that code > into modules and then import in whatever applications need the > functionality. Of course, you can also make internal HTTP requests from one > application to another (or use an RPC mechanism). > How would such code access the DB? By putting the define_tables-type code at the module top-level? Or by putting it in a function and having every db-accessing function call "db = get_DB()" at the beginning? That seems similar to what I'm doing, except that the code is in a controller instead of a module. It seems the bottom line is that there is no way for a controller to internally specify a "dependency" on particular models. The normal web2py mechanism will run the right model files on a regular HTTP request (based on the naming conventions), but if you want to call the controller file some other way, it will have to run the model-creation code itself, even if that code has already been run in another controller. There isn't a way to say "if such-and-such tables have already been created, give me the existing db object; otherwise, create them now". Is that right? Thanks for continuing to help me suss this out. I recognize that what I'm doing is somewhat going against the grain of web2py, but I'd still like to find the smoothest way to get the inter-controller cooperation I'm looking fir. -- Resources: - http://web2py.com - http://web2py.com/book (Documentation) - http://github.com/web2py/web2py (Source code) - https://code.google.com/p/web2py/issues/list (Report Issues) --- You received this message because you are subscribed to the Google Groups "web2py-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to web2py+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.