Re: [flask] Werkzeug routing (long)
- From:
- Davide Muzzarelli
- Date:
- 2010-08-27 @ 19:06
In data venerdì 27 agosto 2010 18:31:19, Armin Ronacher ha scritto:
> That is a well known problem and should be addressed soon. But we have
> to know exactly how people want to implement pluggable applications so
> we would love to collect usecases.
>
> Maybe you could explain your common application layout and how Flask
> could adapt to that.
Ok!
Sorry in advance for my english.
I configure all the application from the settings file. All is explicit so I can
do special things if I need it, like for larger applications.
With this method I can use a simple approach for a simple application, or a
complex approach for a big application.
== STRUCTURE ==
My website:
/mysite
/__init__.py
/manage.py
/views.py
/urls.py
/models.py
/templates
/default.html # this replace the default.html template of the pages
module.
If I have a part of an application that I want to reuse, I create a classic
python package. There is no need to register the package. With this method,
the reusable module may reside in a package, a single file, in sparse files in
the filesystem or also in pickled objects too! Very flexible and very easy to
understand.
Example of a reusable package of modules accessible from the standard Python
path:
/extramodules
/__init__.py # empty
/news # example of a minimal module
/__init__.py # contain some view and some models
/news/news.html
/news/news_list.html
/pages # example of a normal module
/__init__.py # empty
/views.py
/models.py
/contexts.py
/utils.py
/templates
/default.html
/pages/contacts.html
/blog # example of a bigger module
/__init__.py # may contain a Flask extention
/views
/frontend.py
/admin.py
/feeds.py
/models
/simple.py
/complex.py
/contexts.py
/commands.py
/utils.py
/urls.py
/templates
/main.html
/blog/post.html
/blog/post_list.html
/news/news_list.html # this replace the news_list.html template
of the news module
== SETTINGS ==
The settings can be imported like the actual Flask behavior: from the same
executable application file or from another file.
In the settings I can load the models that I need:
MODELS = ['news', 'pages.models', 'blog.simple']
...but if I want to use the full power of the blog module:
MODELS = ['news', 'pages.models', 'blog.complex']
In the settings I can also chose what template directory I want to use, I can
also use an external directory in a custom location:
TEMPLATES = ['/fullpath/mysite/templates',
'/systempath/python/extramodules/blog/templates', ...]
It is still possible to use a simple trick to set the fullpath using the os
module, or using an helper function.
URLS = 'mysite.urls.get_url_map' # Import path of urls, pass the "app"
parameter if it is a callable, so I can use it from a local variable/function
or an external file
These are really necessary:
STATIC_ROOT = '/fullpath/mysite/static_files'
STATIC_PATH = '/media'
Some template plugins, very easy to add:
TEMPLATE _CONTEXTS = ['extramodules.news.CONTEXTS',
'extramodules.blog.get_contexts'] # List of variables or callables for the
template engine.
TEMPLATE_FILTERS = [] # the same thing of template contexts
For the middleware in the same manner:
MIDDLEWARE = ['import.from.string', or.from.object]
The parameters are easy to understand an the developer can pick only what he
need, in the manner that he want.
== SETTINGS HELPERS - YOUR PLUGGABLE APPLICATIONS METHODS ==
A simple function could create the behavior that we want like Django
applications, Flask modules and so on.
In a very simple way (also an extention can do it):
from flask.modules import setup_flask_like_modules
URLS, MODELS, TEMPLATES, TEMPLATE_CONTEXTS, MIDDLEWARE =
setup_flask_like_modules('extramodules.news', 'extramodules.blog')
or
from flask.modules import setup_django_like_modules
URLS, MODELS, TEMPLATES, TEMPLATE_CONTEXTS, MIDDLEWARE =
setup_django_like_modules('extramodules.news', 'extramodules.blog')
== URLS AND VIEWS ==
Same as Werkzeug, It is very powerful.
It is still possible to create an helper class that return a Map object that
run like the actual Flask behavior and it is still possible to use the full
power in order to build a big and complex application.
The endpoint could be a string (it will import the function) or a callable. In
the second case it is very easy to keep the views inside an object (a thing
that the Django developers wish since a lot of time! ;)
Example of a complex urls.py file:
from werkzeug.routing import Map, Rule, Subdomain
from extramodules.blog.urls import generic_urls
def get_url_map(app):
rules = [
Rule('/', endpoint='mysite.views.index'),
Subdomain('<string(length=2):lang_code>', generic_urls),
Rule('/news/',
endpoint='extramodules.page.views.page_with_seo_extention'),
]
if app.config['SHOW_HIDDEN_PAGE']:
from mysite import views
rules.append(Rule('/hidden', endpoint=views.hidden_page))
return Map(rules)
== FINAL CONSIDERATION ==
With this method it is possible to give a simple and fast method for a
pluggable application (like Flask modules), or a little more flexible and magic
one (like Django applications), or also a new method or a custom lighweight
setup. Explicit is better than implicit, leaving the developer how to organize
the things.
Davide Muzzarelli
Re: [flask] Werkzeug routing (long)
- From:
- Davide Muzzarelli
- Date:
- 2010-08-28 @ 14:07
I do a fork of Flask for an example.
http://github.com/Davmuz/flask
== CHANGES ==
- The routing is now managed by the Werkzeug's Map and Rule wrappers, and not
by the Flask's layer.
- Is it possible to name the urls and pass the view function by string or by
reference.
- The OPTIONS url parameter is still there, and you can use it also in custom
Map rules.
- The "route" decorator is still mantained, but in @app.url_map.route().
- The Flask.add_url_rule() method no longer exist because it is possible to
add a url simply by Flask.url_map.add().
- The helper url_for() still work.
- The internal Flask.view_functions no longer exist because the view functions
are loaded directly inside the Rules.
- Removed all the Flask's module system, because it will be possible to create
a custom system.
== COMPATIBILITY ==
I mantained the compatibility as possible, the following are the unique
changes. The tests runs but not for static files (because not yet finished).
- Replace the decorator @app.route(...) with @app.url_map.route(...).
- Replace the method app.add_url_rule(...) with:
from flask.wrappers import Rule
app.url_map.add(Rule(...))
== HOW TO ADD A VIEW ==
It is possible to use the app.url_map object or also create a new Map() and
set to it.
By string:
"""
from flask.wrappers import Rule
Rule('/', endpoint='package.module.view')
"""
By reference:
"""
from flask.wrappers import Rule
def index():
return 'Hello'
Rule('/', endpoint=index)
"""
By named reference:
"""
from flask.wrappers import Rule
def index():
return 'Hello'
Rule('/', view_func=index, endpoint='hello index')
"""
By decorator:
"""
from flask.wrappers import Rule
@app.url_map.route('/')
def index():
return 'Hello'
"""
== TODO ==
- Not yet finished with the static url! It will be possible to chose a custom
directory path where are the static files.
- Documentation not updated, I wait if Armin or others likes the things.
Davide Muzzarelli
Re: [flask] Werkzeug routing (long)
- From:
- Davide Muzzarelli
- Date:
- 2010-08-28 @ 14:15
In data sabato 28 agosto 2010 16:07:36, Davide Muzzarelli ha scritto:
> I do a fork of Flask for an example.
>
> http://github.com/Davmuz/flask
Now the flask_tests runs with the static files, all the tests pass.
I'm waiting for comments.
Davide Muzzarelli
www.dav-muz.net
Re: [flask] Werkzeug routing (long)
- From:
- Davide Muzzarelli
- Date:
- 2010-08-28 @ 17:10
In data sabato 28 agosto 2010 16:15:46, Davide Muzzarelli ha scritto:
> In data sabato 28 agosto 2010 16:07:36, Davide Muzzarelli ha scritto:
> > I do a fork of Flask for an example.
> >
> > http://github.com/Davmuz/flask
Now it is possible to change the path to the static directory.
You can pass a relative or an absolute path.
Relative path:
"""
app = Flask(__name__)
app.static_root = 'media'
"""
Absolute path:
"""
app = Flask(__name__)
app.static_root = '/home/user/www/media'
"""
This change is compatible with the past and the current flask_tests.
Davide Muzzarelli
www.dav-muz.net
Re: [flask] Werkzeug routing (long)
- From:
- Armin Ronacher
- Date:
- 2010-08-28 @ 17:11
Hi,
On 2010-08-28 7:10 PM, Davide Muzzarelli wrote:
> Now it is possible to change the path to the static directory.
> You can pass a relative or an absolute path.
I'm quite busy now and can't check that, but make sure to work against
the new-modules branch which already changes behaviour there a bit.
Regards,
Armin
Re: [flask] Werkzeug routing (long)
- From:
- Davide Muzzarelli
- Date:
- 2010-08-28 @ 18:14
In data sabato 28 agosto 2010 19:11:54, Armin Ronacher ha scritto:
> On 2010-08-28 7:10 PM, Davide Muzzarelli wrote:
> > Now it is possible to change the path to the static directory.
> > You can pass a relative or an absolute path.
>
> I'm quite busy now and can't check that, but make sure to work against
> the new-modules branch which already changes behaviour there a bit.
The change is 26d5cde001fc0948c67f
You can cherry pick directly.
I don't found any documentation about new-modules, what change for the end
developer?
Davide Muzzarelli
www.dav-muz.net
Re: [flask] Werkzeug routing (long)
- From:
- Armin Ronacher
- Date:
- 2010-08-28 @ 18:50
Hi,
The new module brach breaks a few things (actually it deprecates) for more
explicit file handling. Currently the static folders are picked up
automatically when a folder named static exists, in that branch this no
longer happens, you have to opt-in static folders for a module.
This change fixes issues with google appengine and multiple modules from
the same folder.
Because it really changes a lot internally from master I would like you to
review if that applies flin new-modules. I can't review that myself
currently due to the lack of a machine with my dev tools.
Regards,
Armin
(sent from a handheld device)
On 28.08.2010, at 20:14, Davide Muzzarelli <d.muzzarelli@dav-muz.net> wrote:
> In data sabato 28 agosto 2010 19:11:54, Armin Ronacher ha scritto:
>> On 2010-08-28 7:10 PM, Davide Muzzarelli wrote:
>>> Now it is possible to change the path to the static directory.
>>> You can pass a relative or an absolute path.
>>
>> I'm quite busy now and can't check that, but make sure to work against
>> the new-modules branch which already changes behaviour there a bit.
>
> The change is 26d5cde001fc0948c67f
> You can cherry pick directly.
>
> I don't found any documentation about new-modules, what change for the end
> developer?
>
> Davide Muzzarelli
> www.dav-muz.net
Re: [flask] Werkzeug routing (long)
- From:
- Davide Muzzarelli
- Date:
- 2010-08-28 @ 18:57
In data sabato 28 agosto 2010 20:50:20, Armin Ronacher ha scritto:
> The new module brach breaks a few things (actually it deprecates) for more
> explicit file handling. Currently the static folders are picked up
> automatically when a folder named static exists, in that branch this no
> longer happens, you have to opt-in static folders for a module.
>
> This change fixes issues with google appengine and multiple modules from
> the same folder.
>
> Because it really changes a lot internally from master I would like you to
> review if that applies flin new-modules. I can't review that myself
> currently due to the lack of a machine with my dev tools.
Thank you Armin, sure I will give some attention.
Davide Muzzarelli
www.dav-muz.net
Re: [flask] Werkzeug routing (long)
- From:
- Dag Odenhall
- Date:
- 2010-08-28 @ 15:07
lör 2010-08-28 klockan 16:07 +0200 skrev Davide Muzzarelli:
> I do a fork of Flask for an example.
>
> http://github.com/Davmuz/flask
>
>
> == CHANGES ==
>
> - The routing is now managed by the Werkzeug's Map and Rule wrappers, and not
> by the Flask's layer.
> - Is it possible to name the urls and pass the view function by string or by
> reference.
> - The OPTIONS url parameter is still there, and you can use it also in custom
> Map rules.
> - The "route" decorator is still mantained, but in @app.url_map.route().
> - The Flask.add_url_rule() method no longer exist because it is possible to
> add a url simply by Flask.url_map.add().
> - The helper url_for() still work.
> - The internal Flask.view_functions no longer exist because the view functions
> are loaded directly inside the Rules.
> - Removed all the Flask's module system, because it will be possible to create
> a custom system.
>
>
> == COMPATIBILITY ==
>
> I mantained the compatibility as possible, the following are the unique
> changes. The tests runs but not for static files (because not yet finished).
>
> - Replace the decorator @app.route(...) with @app.url_map.route(...).
> - Replace the method app.add_url_rule(...) with:
> from flask.wrappers import Rule
> app.url_map.add(Rule(...))
>
>
> == HOW TO ADD A VIEW ==
>
> It is possible to use the app.url_map object or also create a new Map() and
> set to it.
>
> By string:
> """
> from flask.wrappers import Rule
> Rule('/', endpoint='package.module.view')
> """
>
> By reference:
> """
> from flask.wrappers import Rule
> def index():
> return 'Hello'
> Rule('/', endpoint=index)
> """
>
> By named reference:
> """
> from flask.wrappers import Rule
> def index():
> return 'Hello'
> Rule('/', view_func=index, endpoint='hello index')
> """
>
> By decorator:
> """
> from flask.wrappers import Rule
> @app.url_map.route('/')
> def index():
> return 'Hello'
> """
>
>
> == TODO ==
>
> - Not yet finished with the static url! It will be possible to chose a custom
> directory path where are the static files.
> - Documentation not updated, I wait if Armin or others likes the things.
>
>
> Davide Muzzarelli
You do realize add_url_rule forwards options to Rule()? You can add
view_functions later, by endpoint. If you don't want view_functions,
maybe you'd be more comfortable in raw Werkzeug without Flask?
Re: [flask] Werkzeug routing (long)
- From:
- Davide Muzzarelli
- Date:
- 2010-08-28 @ 16:32
Hi Dag,
I'm sorry in advance if I do not understand well.
In data sabato 28 agosto 2010 17:07:17, Dag Odenhall ha scritto:
> You do realize add_url_rule forwards options to Rule()?
For me add_url_rule is now unuseful because it adds the OPTIONS method, now it
is added by the Rule class automatically. Actually, without this necessity, it
is only a void wrapper over url_map.add().
Now you can use url_map.add(Rule(...)) instead of add_url_rule(...). It is
more explicit and, if you want, you can now also add others rules factories
like Subdomain, Submount and EndpointPrefix.
> You can add view_functions later, by endpoint.
view_functions was useful for url_for and for match the view, but this method
does not permit to use more complex custom urls, so I removed it. Whis this it
is impossible to use custom urls.
Now the match is made by the endpoint property, and the view is stored
directly inside the Rule (view_func property), this is the system that replace
the view_functions.
I used this Werkzeug snippet:
http://dev.pocoo.org/projects/werkzeug/wiki/UsingNamedRulesWithWerkzeugRouting
The Flask dispatch_request() simply call the view_func of the matched rule.
This also open the possibility of named urls and views passed by string.
> If you don't want view_functions, maybe you'd be more comfortable in raw
> Werkzeug without Flask?
Yes, a lot, because the Werkzeug system can scale for a bigger application or
pluggables.
This modification is soft because you can still use the old easy Flask system
(also old Flask modules, but I've not implemented it yet).
Davide Muzzarelli
www.dav-muz.net
Re: [flask] Werkzeug routing (long)
- From:
- Dag Odenhall
- Date:
- 2010-08-28 @ 17:07
lör 2010-08-28 klockan 18:32 +0200 skrev Davide Muzzarelli:
> Hi Dag,
> I'm sorry in advance if I do not understand well.
>
> In data sabato 28 agosto 2010 17:07:17, Dag Odenhall ha scritto:
> > You do realize add_url_rule forwards options to Rule()?
>
> For me add_url_rule is now unuseful because it adds the OPTIONS method, now it
> is added by the Rule class automatically. Actually, without this necessity, it
> is only a void wrapper over url_map.add().
I think you can override so it does not add OPTIONS if you don't want
that (why not?)
>
> Now you can use url_map.add(Rule(...)) instead of add_url_rule(...). It is
> more explicit and, if you want, you can now also add others rules factories
> like Subdomain, Submount and EndpointPrefix.
Why the need for Rule() here though? Or do you expect one might want to
add something other than a Rule()?
>
> > You can add view_functions later, by endpoint.
>
> view_functions was useful for url_for and for match the view, but this method
> does not permit to use more complex custom urls, so I removed it. Whis this it
> is impossible to use custom urls.
I don't get what you mean. You can do any URL with Flask that you can do
with Werkzeug, no?
>
> Now the match is made by the endpoint property, and the view is stored
> directly inside the Rule (view_func property), this is the system that replace
> the view_functions.
> I used this Werkzeug snippet:
> http://dev.pocoo.org/projects/werkzeug/wiki/UsingNamedRulesWithWerkzeugRouting
> The Flask dispatch_request() simply call the view_func of the matched rule.
>
> This also open the possibility of named urls and views passed by string.
>
> > If you don't want view_functions, maybe you'd be more comfortable in raw
> > Werkzeug without Flask?
>
> Yes, a lot, because the Werkzeug system can scale for a bigger application or
> pluggables.
> This modification is soft because you can still use the old easy Flask system
> (also old Flask modules, but I've not implemented it yet).
>
>
> Davide Muzzarelli
> www.dav-muz.net
Re: [flask] Werkzeug routing
- From:
- Davide Muzzarelli
- Date:
- 2010-08-28 @ 18:05
In data sabato 28 agosto 2010 19:07:29, Dag Odenhall ha scritto:
> I think you can override so it does not add OPTIONS if you don't want
> that (why not?)
Yes, in this case you can ovverride the flask.wrappers.Rule class.
But I like OPTIONS and I keep it in the flask.wrappers.Rule class, so you can
reuse it for custom routers (see the flollowing question).
There is more: I added url names and views loading from string.
> Why the need for Rule() here though? Or do you expect one might want to
> add something other than a Rule()?
Because it is the unique way to use Subdomain, Submount, EndpointPrefix and
custom RuleFactories.
It is also possible to create different module systems than the Flask's one.
In my specific case, with this change I can use pluggables, make bigger
applications in their different ways and customize every application with less
code reusing my packages.
For a simple example: I have a News plugin with models, views and standard
urls. So I can use the standard configuration for some websites; for some other
tailored websites I can configure the urls with different names and use more
advanced versions of the views with very few lines of code. I do this often
for my clients.
The real power is to use a pluggable and customize it in few lines without
touch it and without hacks! Actually I do this since some year.
> I don't get what you mean. You can do any URL with Flask that you can do
> with Werkzeug, no?
No. Before this, you can't add Werkzeug Rules, Maps or other RulesFactories.
After this change you can still use the old Flask method but also do things in
more advanced methods wihout hacks.
I've just removed some limits keeping the compatibility with the past as
possible. You can read one of my previous email (the long one) to see where I
wish to go, sorry if I was not enough clear.
Tell me if there are more things obscure or if you want some example, I'm
really open because I need it.
Davide Muzzarelli
www.dav-muz.net