Is it necesary that all views should be in a single file

102 views
Skip to first unread message

Krishnakant Mane

unread,
Nov 9, 2015, 12:39:40 PM11/9/15
to pylons-discuss
Hello,
Can have I have a set of modules in a package containing my view classes?
I had asked this same question before regarding normal views.
I don't feel that it is a good idea to have all views in a single views.py file.
Happy hacking.
Krishnakant.

Jonathan Vanasco

unread,
Nov 9, 2015, 12:54:19 PM11/9/15
to pylons-discuss
You can have views in multiple files, and even different packages.  

`views.py` is just a "scaffold" or reference implementation.

IIRC, Pyramid will automatically scan either `views.py` or a  `views/` package directory and subdirectories by default.  (ie, everything with an `__init__.py`) 

If you want to scan other packages/directories, you can even use dotted notation to explicitly scan them as well:

    config.scan("myapp.views_a")

Bert JW Regeer

unread,
Nov 9, 2015, 3:14:14 PM11/9/15
to pylons-...@googlegroups.com

> On Nov 9, 2015, at 10:54 , Jonathan Vanasco <jona...@findmeon.com> wrote:
>
> You can have views in multiple files, and even different packages.
>
> `views.py` is just a "scaffold" or reference implementation.
>
> IIRC, Pyramid will automatically scan either `views.py` or a `views/` package directory and subdirectories by default. (ie, everything with an `__init__.py`)

This is not done by default. However most examples have config.scan() which will scan all packages it finds.

>
> If you want to scan other packages/directories, you can even use dotted notation to explicitly scan them as well:
>
> config.scan("myapp.views_a")
>
>
> --
> You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discus...@googlegroups.com.
> To post to this group, send email to pylons-...@googlegroups.com.
> Visit this group at http://groups.google.com/group/pylons-discuss.
> For more options, visit https://groups.google.com/d/optout.

Krishnakant Mane

unread,
Nov 11, 2015, 4:26:10 AM11/11/15
to pylons-discuss
So should I do config.scann for the views package?
Or is it that Pyramid will automatically see my package name?
I am still confused how Pyramid will automatically know which files contain my view code?

kk

unread,
Nov 11, 2015, 4:47:21 AM11/11/15
to pylons-discuss
yes and I also forgot to ask, how will it affect my roots?
Happy hacking.
Krishnakant.
--
You received this message because you are subscribed to a topic in the Google Groups "pylons-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/pylons-discuss/wL2P3BBdI6Y/unsubscribe.
To unsubscribe from this group and all its topics, send an email to pylons-discus...@googlegroups.com.

Paul Everitt

unread,
Nov 11, 2015, 6:51:45 AM11/11/15
to pylons-...@googlegroups.com

When you are starting, most people define their routes in their __init__ main() function, and their views in a views.py module which they read with config.scan(‘.views’). You can go a LONG way with just this. Feel free to stop reading at this point. :)

Later, people start organizing their code base by component: a todo directory, a user directory, etc. Each of those then have a views.py module in them. However, they still leave the route definition in the top-level __init__.py, to control ordering.

After that, though, there is a further level of Pyramid zen:

- Have a todo/__init__.py with an includeme function, which is the single place for wiring up everything in the todo subpackage

- The includeme function does the view registration

- It *also* does route definition

- The top-level package then pulls in todo etc. using config.include with a route prefix to avoid ordering and collision problems:


—Paul

You received this message because you are subscribed to the Google Groups "pylons-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pylons-discus...@googlegroups.com.

kk

unread,
Nov 11, 2015, 7:15:11 AM11/11/15
to pylons-...@googlegroups.com
Hi Paul, thanks for clearing this out for me,
However I have a couple of confusions which I have added in-line to your reply.




On Wednesday 11 November 2015 05:21 PM, Paul Everitt wrote:

When you are starting, most people define their routes in their __init__ main() function, and their views in a views.py module which they read with config.scan(‘.views’). You can go a LONG way with just this. Feel free to stop reading at this point. :)
:) Well, My application is big enough so I have to stop reading at this point.



Later, people start organizing their code base by component: a todo directory, a user directory, etc. Each of those then have a views.py module in them. However, they still leave the route definition in the top-level __init__.py, to control ordering.

Oh,  don't understand this, because I would still need scanning right?  So do I scann packages or individual files, as in package/module?
And I would like to know if I have to do the double work of first writing the roots and then also do the
@view_config(route_name=view_name)?
This is a different query all together and I did mail it on a different thread, but now that we are discussing, I thought of asking this.
The Reason I am asking is can I just use config.add_view and not write roots at all?



After that, though, there is a further level of Pyramid zen:

- Have a todo/__init__.py with an includeme function, which is the single place for wiring up everything in the todo subpackage

- The includeme function does the view registration

So again the same question, will I have to do the double work under this situation or will I just do config.ad_view() in the includeme function?



- It *also* does route definition

- The top-level package then pulls in todo etc. using config.include with a route prefix to avoid ordering and collision problems:

So the top level package will still need roots is it?
My condition is very simple, I will just have a single package with many modules, each being a class based view.
For example a view_voucher.py having add, update, insert and delete (aka crud ) system.
Similarly there will be a view_user, view_account view_product etc.

So I am trying to figure out how a single package can be scanned, or do I have to write individual config.add_view statements for all my package/module/view_function or class?
I am sorry if I am sounding too naive, but  have used Pylons before and the system was very simple, there used to be a controllers directory and I had all my controller modules/classes there.
 

Happy hacking.
Krishnakant.

Paul Everitt

unread,
Nov 11, 2015, 7:26:23 AM11/11/15
to pylons-...@googlegroups.com

> On Nov 11, 2015, at 7:14 AM, kk <krm...@gmail.com> wrote:
>
> Hi Paul, thanks for clearing this out for me,
> However I have a couple of confusions which I have added in-line to your reply.
>
>
>
> On Wednesday 11 November 2015 05:21 PM, Paul Everitt wrote:
>>
>> When you are starting, most people define their routes in their __init__ main() function, and their views in a views.py module which they read with config.scan(‘.views’). You can go a LONG way with just this. Feel free to stop reading at this point. :)
> :) Well, My application is big enough so I have to stop reading at this point.
>
>>
>> Later, people start organizing their code base by component: a todo directory, a user directory, etc. Each of those then have a views.py module in them. However, they still leave the route definition in the top-level __init__.py, to control ordering.
>
> Oh, don't understand this, because I would still need scanning right? So do I scann packages or individual files, as in package/module?
> And I would like to know if I have to do the double work of first writing the roots and then also do the
> @view_config(route_name=view_name)?
> This is a different query all together and I did mail it on a different thread, but now that we are discussing, I thought of asking this.
> The Reason I am asking is can I just use config.add_view and not write roots at all?

No, you still need to do routes, for the reasons explained in the other email.

(Pyramid does have a non-route approach to URL mapping called traversal, but you should only introduce it after learning routes.)
>
>>
>> After that, though, there is a further level of Pyramid zen:
>>
>> - Have a todo/__init__.py with an includeme function, which is the single place for wiring up everything in the todo subpackage
>>
>> - The includeme function does the view registration
>
> So again the same question, will I have to do the double work under this situation or will I just do config.ad_view() in the includeme function?

Yes, although it isn’t “double work”. A route is different than a view, because one route can lead to multiple views. It’s like asking “can’t you just do my database, template, view, and route in one line?” They are different things.

Doing routes and views as one thing introduces problems and magic. Python doesn’t like magic. Python believes explicit is better than implicit. So does Pyramid.

>
>>
>> - It *also* does route definition
>>
>> - The top-level package then pulls in todo etc. using config.include with a route prefix to avoid ordering and collision problems:
>
> So the top level package will still need roots is it?
> My condition is very simple, I will just have a single package with many modules, each being a class based view.
> For example a view_voucher.py having add, update, insert and delete (aka crud ) system.

Do you have anything about a “Voucher” besides views? E.g. templates, database models, tests, etc. If so, you might want an organization of:

./app
__init__.py
/voucher
__init__.py
views.py
templates/
models.py
tests

In this approach:

- voucher/__init__.py does all the route and view registration for Voucher inside an “includeme”:

http://docs.pylonsproject.org/projects/pyramid-cookbook/en/latest/configuration/whirlwind_tour.html#the-includeme-convention

- app/__init__.py uses config.include(‘.voucher’) etc. for each part of your application

> Similarly there will be a view_user, view_account view_product etc.
>
> So I am trying to figure out how a single package can be scanned, or do I have to write individual config.add_view statements for all my package/module/view_function or class?
> I am sorry if I am sounding too naive, but have used Pylons before and the system was very simple, there used to be a controllers directory and I had all my controller modules/classes there.

Yes, magic directory names and magic scanning. If your goal is the least amount of work:

- __init__.py does all the config.add_route (you can’t avoid that duplication)

- __init__.py does config.scan(‘.’) to go look everywhere for @view_config

—Paul

Jonathan Vanasco

unread,
Nov 11, 2015, 1:06:19 PM11/11/15
to pylons-discuss
Ack!  Sorry, I forgot about `config.scan('views')`.  Thanks for correcting me.

Another way of looking at the "route" vs "views" is this:

A route is essentially just a shorthand name for a url (which may contain different patterns), and needs to be handled differently in multiple contexts.

Let's say you have defined this simple "route":

    config.add_route("splash", "/splash")

Or you define an advanced route that uses regex patterns:

    config.add_route("splash_action", "/splash/{splash_action}")

You may want to register the route to multiple "views" depending on the context, for example you can handle routes depending on the request method:

    @view_config(route_name="splash", request_method="GET")
    def handle_splash_get(...):
       pass

    @view_config(route_name="splash", request_method ="POST")
    def handle_splash_post(...):
       pass

If Pyramid didn't require named routes and instead supported URLs in the view_config, it would be incredibly hard to manage your project as it grows AND you would not be able to influence the order in which similar routes are resolved.

So what might seem as a bit more work today, is actually not really much work at all -- and it saves you a lot of time and energy tomorrow.

kk

unread,
Nov 11, 2015, 1:38:16 PM11/11/15
to pylons-...@googlegroups.com



On Wednesday 11 November 2015 11:36 PM, Jonathan Vanasco wrote:
> Ack! Sorry, I forgot about `config.scan('views')`. Thanks for
> correcting me.
>
> Another way of looking at the "route" vs "views" is this:
>
> A route is essentially just a shorthand name for a url (which may
> contain different patterns), and needs to be handled differently in
> multiple contexts.


So view_config is the decorator which is not just an anotation but an
important link as in the context for rooting the request to a view.
Is that correct?
Happy hacking.
Krishnakant.

Jonathan Vanasco

unread,
Nov 11, 2015, 1:58:23 PM11/11/15
to pylons-discuss
@view_config is a decorator that registers the view callable function ( http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/viewconfig.html#adding-view-configuration-using-the-view-config-decorator )

The various arguments trigger the view.

There are other ways to register a view (such as `config.add_view`), but `@view_config` is very popular.

kk

unread,
Nov 11, 2015, 2:02:05 PM11/11/15
to pylons-...@googlegroups.com

Thanks,


On Thursday 12 November 2015 12:28 AM, Jonathan Vanasco wrote:
> @view_config is a decorator that registers the view callable function
> ( http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/viewconfig.html#adding-view-configuration-using-the-view-config-decorator
> )
>
> The various arguments trigger the view.

But I read that this is a slow way specially during the startup of the
web app? Is that correct?
>
> There are other ways to register a view (such as `config.add_view`),
> but `@view_config` is very popular.
> --
So when using add_view, the rooting happens in the same line of code or
is it still done at a different place?
Happy hacking.
Krishnakant.


Paul Everitt

unread,
Nov 11, 2015, 2:09:50 PM11/11/15
to pylons-...@googlegroups.com

> On Nov 11, 2015, at 2:01 PM, kk <krm...@gmail.com> wrote:
>
>
> Thanks,
>
>
> On Thursday 12 November 2015 12:28 AM, Jonathan Vanasco wrote:
>> @view_config is a decorator that registers the view callable function ( http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/viewconfig.html#adding-view-configuration-using-the-view-config-decorator )
>>
>> The various arguments trigger the view.
>
> But I read that this is a slow way specially during the startup of the web app? Is that correct?

The speed hit on startup comes from the other side, the part doing the config.scan(). It’s a very small hit only when you have a huge code base (lots of files to scan). Easily fixed as well. So don’t be afraid of @view_config. :)

>>
>> There are other ways to register a view (such as `config.add_view`), but `@view_config` is very popular.
>> --
> So when using add_view, the rooting happens in the same line of code or is it still done at a different place?

There are two parts to the dance:

- Routing looks at the URL and selects a route name based on the URL pattern and the order the routes were registered. Your config.add_route statements register those route names.

- Once you have a route name, you then need a view from the list of views registered for that route name. Your config.add_view (or @view_config) statements register views for a route name.

Jonathan, I liked your explanation of “a route is a way to make an identifier on a URL pattern”.

—Paul

kk

unread,
Nov 11, 2015, 2:20:29 PM11/11/15
to pylons-...@googlegroups.com

Thanks Paul and jon.
Now I understand the beauty of it.
In an oop terminology, this approach means that the root name can become
polimorfic.
So that same name can be registed with various view functions and and
the right one will be called depending on the request type or difference
in parameters.
Is that correct?
If so then my question is how will the same root name help in making
code simple, except readability?
I mean, I may as well have different root names with different patterns
to make things more explicit.
As it is some difference is going to be there in the url pattern when a
request reaches some view function, then how will the same name help?
Happy hacking.
Krishnakant.

Paul Everitt

unread,
Nov 11, 2015, 2:37:01 PM11/11/15
to pylons-...@googlegroups.com
On Nov 11, 2015, at 2:20 PM, kk <krm...@gmail.com> wrote:


Thanks Paul and jon.
Now I understand the beauty of it.
In an oop terminology, this approach means that the root name can become polimorfic.
So that same name can be registed with various view functions and and the right one will be called depending on the request type or difference in parameters.
Is that correct?

Well said! And yes, that’s correct. The framework chooses the matching route definition, then chooses the best-match view. I little like CSS rules.

If so then my question is how will the same root name help in making code simple, except readability?

Look at the view class in bullet point 3 at:


It uses one route_name (applied on the entire view class) with all the views related to it:

- def hello is used on GET

- def edit is used on POST

- def delete is used when POST was done with a certain button

- def home is the special case on the view, uses a different route name

In a REST-style ToDo application, you could have one route:

/todo/{id}

…that handled views for:

- View the todo (GET)

- Edit the todo (PUT)

- Delete the todo (DELETE)

Or in a non-REST, you could use (like the URL above) presence of which button was clicked.

I mean, I may as well have different root names with different patterns to make things more explicit.

If you never have any variations, meaning a very simple application, than that is indeed simple.

What happens, though, is people wind up with branches in their views to try and decide which subview they are in:

if request.method == ‘GET’:
# return a form
elif request.method == ‘POST’ and request.params.get(‘button.submit’):
# process the submit
elif request.method == ‘POST’ and requet.params.get(‘button.cancel’:
# clear the session and go to another URL
elif request.xhr:
# Oh, we’re a REST request, we should do JSON

Not only is that ugly on the face of it, test writing becomes a fiasco. Whenever you see something in Pyramid that looks like extra work, many times it is to make test writing easier. :)

As it is some difference is going to be there in the url pattern when a request reaches some view function, then how will the same name help?
Happy hacking.

It isn’t only in the URL pattern. It’s in the HTTP method (GET, POST, PUT, DELETE, and nowadays PATCH). It’s in the form data that was submitted, to see which button was clicked. It’s in forms vs. Ajax/REST (thus an HTTP header.)

I believe you badly want to believe one URL == one route == one view. I suggest you go that direction, as it makes the most sense. Later, when you start to feel like your views have grown 9 arms, step back and think: should I have different views for different flavors of request?

—Paul

Krishnakant.


On Thursday 12 November 2015 12:39 AM, Paul Everitt wrote:
On Nov 11, 2015, at 2:01 PM, kk <krm...@gmail.com> wrote:


Thanks,


On Thursday 12 November 2015 12:28 AM, Jonathan Vanasco wrote:
@view_config is a decorator that registers the view callable function ( http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/viewconfig.html#adding-view-configuration-using-the-view-config-decorator )

The various arguments trigger the view.
But I read that this is a slow way specially during the startup of the web app?  Is that correct?
The speed hit on startup comes from the other side, the part doing the config.scan(). It’s a very small hit only when you have a huge code base (lots of files to scan). Easily fixed as well. So don’t be afraid of @view_config. :)

There are other ways to register a view (such as `config.add_view`), but `@view_config` is very popular.
--
So when using add_view, the rooting happens in the same line of code or is it still done at a different place?
There are two parts to the dance:

- Routing looks at the URL and selects a route name based on the URL pattern and the order the routes were registered. Your config.add_route statements register those route names.

- Once you have a route name, you then need a view from the list of views registered for that route name. Your config.add_view (or @view_config) statements register views for a route name.

Jonathan, I liked your explanation of “a route is a way to make an identifier on a URL pattern”.

—Paul


kk

unread,
Nov 11, 2015, 2:50:29 PM11/11/15
to pylons-...@googlegroups.com
Thank you Paul.
That sorts it out for me.
I am actually going to write a RESTful service using perhaps cornice with Pyramid.
You are right in saying that CRUD kind of system fits in nicely with this approach.
I will try some code and see how it feels.
Thanks a million.
Happy hacking.
Krishnakant.
Ps:
I did a top posting a couple of times and I am sorry for that.
Basically I am totally blind and some times my screen reader reads out things in an odd way after a few mails are written in-line as replies to replies.
You received this message because you are subscribed to a topic in the Google Groups "pylons-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/pylons-discuss/wL2P3BBdI6Y/unsubscribe.
To unsubscribe from this group and all its topics, send an email to pylons-discus...@googlegroups.com.

Mike Orr

unread,
Nov 11, 2015, 3:27:37 PM11/11/15
to pylons-...@googlegroups.com
It doesn't automatically know. There are two ways to register views:

1) Use 'config.add_view()' for every view.

2) Decorate the views with '@view_config' and then run 'config.scan()'
over the module or package. The scanning does the add_view's for you.
You can specify which package to scan, and it will scan all modules
and subpackages under it.

Some people prefer one way, and some the other. I used to use
'@view_config' but I'm currently using 'config.add_view()' because
it's less magical.

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

kk

unread,
Nov 11, 2015, 3:36:08 PM11/11/15
to pylons-...@googlegroups.com


Hi Mike,
How is config.add_view less magical?
And which is actually the place to write add_view?
Do i put this decorator just above the view function just like
view_config is put?
Is the only difference in using or not using the scann command?
Happy hacking.
Krishnakant.

Mike Orr

unread,
Nov 12, 2015, 11:48:36 PM11/12/15
to pylons-...@googlegroups.com
With 'config.add_view', you write the method calls yourself, so it's
clear in the code exactly which views are being activated when, and if
an exception occurs it points to that specific line.

With 'config.scan', it lists the modules internally and imports them
using a kind of hack, and you have to trust that the scanner will find
all the declarations and correctly add them, or else you have to trace
why it didn't. It also imports every module it scans, which can have
side effects if the module contains global initialization code. When
you import a module, you know exactly when it will be imported. When
scan imports a module, it just happens sometime during the scan. I
don't want to make a big deal out of it. 'config.scan' works; a lot of
people use it.

You put the calls in your main function, or in something that your
main function calls or includes. If you have a pageful of routes and a
lot of views, you might have a routes.py and a views/__init__.py . My
current application has a lot of configuration (authorization,
sessions, custom Request methods, etc), so I put the miscellaneous
configuration modules in appname/app/, so I have
appname/app//routes.py and appname/app/views.py (separate from the
appname/views/ package where the views themselves are). You can put
the views in a regular function with a 'config' argument, or put them
in an 'includeme(config)' function and use
'config.include(the_module)' -- they both do the same thing.
> --
> You received this message because you are subscribed to the Google Groups
> "pylons-discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to pylons-discus...@googlegroups.com.
> To post to this group, send email to pylons-...@googlegroups.com.
> Visit this group at http://groups.google.com/group/pylons-discuss.
> For more options, visit https://groups.google.com/d/optout.



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

kk

unread,
Nov 13, 2015, 7:36:05 AM11/13/15
to pylons-...@googlegroups.com


Thanks Mike for the clarification,
So let's say I have a project and under it I create a folder called views/
Now in the __init__.py file I must have the includeme function, is that
correct?
I am going to have a lot of modules in the views folder, so I thought
this makes sence.
If this is correct, then in my main project package I will have the
routes.py is what I feel.
I just don't understand if the views package must be imported somewhere
or is it insignificant, given that routes.py has all the routes to any
module?
Let's say my views/ directory contains __init__.py, accounts.py and
vouchers.py (the latter 2 being view classes )
So I want to know where do I write the config.add_view function and and
how routes will be associated with them?
Could you make this clear with an example setup given my project views/
package as I mentioned above?
Of course i will have templates directory and all other things which a
basic scaffold will provide.
I think being explicit about the order and control over the imports
sounds better to me than scann, although I might be wrong in my
understanding.
Happy hacking.
Krishnakant,

Mike Orr

unread,
Nov 14, 2015, 8:53:01 AM11/14/15
to pylons-...@googlegroups.com
# myapp/views/accounts.py
class AccountView(object):
def __init__(self, request):
self.request = request

def hello(self):
...

# myapp/views/__init__.py
def includeme(config):
import myapp.views.accounts
config.add_view(myapp.views.accounts.AccountView,
attr="hello", route_name="home")

# myapp/routes.py
def includeme(config):
config.add_route("hello", "/hello")

# myapp/__init__.py
def main(settings):
import myapp.routes
import myapp.views
...
config.include(myapp.routes)
config.include(myapp.views)


You can of course use absolute or relative imports, or string names.
config.add_view("myapp.views.accounts.AccountView", ...)

The imports are in functions to avoid complications when an init
module imports its own child. (If the import is at global level, the
bottom of the init module won't have executed yet, and if the child
also imports its parent, it creates a circular import, where the
bottom of the child's module isn't executed yet either, so any globals
below that point don't exist yet and can't be depended on).
--
Mike Orr <slugg...@gmail.com>

kk

unread,
Nov 14, 2015, 10:13:32 AM11/14/15
to pylons-...@googlegroups.com

Hi and thanks.


On Saturday 14 November 2015 07:22 PM, Mike Orr wrote:
> # myapp/views/accounts.py
> class AccountView(object):
> def __init__(self, request):
> self.request = request
>
> def hello(self):
> ...

This is pretty clear.
>
> # myapp/views/__init__.py
> def includeme(config):
> import myapp.views.accounts
> config.add_view(myapp.views.accounts.AccountView,
> attr="hello", route_name="home")

What is home in this line? is it the route name?
>
> # myapp/routes.py
> def includeme(config):
> config.add_route("hello", "/hello")

I again don't see where the home attribute fits in here, I seem to get lost.
>
> # myapp/__init__.py
> def main(settings):
> import myapp.routes
> import myapp.views
> ...
> config.include(myapp.routes)
> config.include(myapp.views)
>

This is clear too.

Happy hacking.
Krishnakant.

Mike Orr

unread,
Nov 15, 2015, 1:47:06 PM11/15/15
to pylons-...@googlegroups.com
>> # myapp/views/__init__.py
>> def includeme(config):
>> import myapp.views.accounts
>> config.add_view(myapp.views.accounts.AccountView,
>> attr="hello", route_name="home")
>
>
> What is home in this line? is it the route name?

Yes. So the route should have been 'config.add_route("home", "/")'
Reply all
Reply to author
Forward
0 new messages