Browse Source

Added lazyloading pattern and explicit chapter links in tutorial.

This fixes #49.
pull/1638/head
Armin Ronacher 15 years ago
parent
commit
9d19b77acf
  1. 2
      docs/_themes
  2. 4
      docs/conf.py
  3. 1
      docs/patterns/index.rst
  4. 104
      docs/patterns/lazyloading.rst
  5. 4
      docs/tutorial/css.rst
  6. 4
      docs/tutorial/dbcon.rst
  7. 4
      docs/tutorial/dbinit.rst
  8. 4
      docs/tutorial/folders.rst
  9. 4
      docs/tutorial/introduction.rst
  10. 4
      docs/tutorial/schema.rst
  11. 4
      docs/tutorial/setup.rst
  12. 4
      docs/tutorial/templates.rst
  13. 2
      docs/tutorial/testing.rst
  14. 4
      docs/tutorial/views.rst
  15. 1
      examples/minitwit/minitwit.py

2
docs/_themes

@ -1 +1 @@
Subproject commit 09eeca526b2b5675cc29f45917f5d0f795395035
Subproject commit 91eee537e91594f752224a5847719f6d4fb38c2d

4
docs/conf.py

@ -140,7 +140,7 @@ html_sidebars = {
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
html_use_modindex = False
# If false, no index is generated.
#html_use_index = True
@ -152,7 +152,7 @@ html_sidebars = {
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
html_show_sphinx = False
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True

1
docs/patterns/index.rst

@ -28,3 +28,4 @@ Snippet Archives <http://flask.pocoo.org/snippets/>`_.
flashing
jquery
errorpages
lazyloading

104
docs/patterns/lazyloading.rst

@ -0,0 +1,104 @@
Lazily Loading Views
====================
Flask is usually used with the decorators. Decorators are simple and you
have the URL right next to the function that is called for that specific
URL. However there is a downside to this approach: it means all your code
that uses decorators has to be imported upfront or Flask will never
actually find your function.
This can be a problem if your application has to import quick. It might
have to do that on systems like Google's AppEngine or other systems. So
if you suddenly notice that your application outgrows this approach you
can fall back to a centralized URL mapping.
The system that enables having a central URL map is the
:meth:`~flask.Flask.add_url_rule` function. Instead of using decorators,
you have a file that sets up the application with all URLs.
Converting to Centralized URL Map
---------------------------------
Imagine the current application looks somewhat like this::
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
pass
@app.route('/user/<username>')
def user(username):
pass
Then the centralized approach you would have one file with the views
(`views.py`) but without any decorator::
def index():
pass
def user(username):
pass
And then a file that sets up an application which maps the functions to
URLs::
from flask import Flask
from yourapplication import views
app = Flask(__name__)
app.add_url_rule('/', view_func=views.index)
app.add_url_rule('/user/<username>', view_func=views.user)
Loading Late
------------
So far we only split up the views and the routing, but the module is still
loaded upfront. The trick to actually load the view function as needed.
This can be accomplished with a helper class that behaves just like a
function but internally imports the real function on first use::
from werkzeug import import_string, cached_property
class LazyView(object):
def __init__(self, import_name):
self.__module__, self.__name__ = import_name.rsplit('.', 1)
self.import_name = import_name
@cached_property
def view(self):
return import_string(self.import_name)
def __call__(self, *args, **kwargs):
return self.view(*args, **kwargs)
What's important here is is that `__module__` and `__name__` are properly
set. This is used by Flask internally to figure out how to do name the
URL rules in case you don't provide a name for the rule yourself.
Then you can define your central place to combine the views like this::
from flask import Flask
from yourapplication.helpers import LazyView
app = Flask(__name__)
app.add_url_rule('/',
view_func=LazyView('yourapplication.views.index'))
app.add_url_rule('/user/<username>',
view_func=LazyView('yourapplication.views.user'))
You can further optimize this in terms of amount of keystrokes needed to
write this by having a function that calls into
:meth:`~flask.Flask.add_url_rule` by prefixing a string with the project
name and a dot, and by wrapping `view_func` in a `LazyView` as needed::
def url(url_rule, import_name, **options):
view = LazyView('yourapplication.' + import_name)
app.add_url_rule(url_rule, view_func=view, **options)
url('/', 'views.index')
url('/user/<username>', 'views.user')
One thing to keep in mind is that before and after request handlers have
to be in a file that is imported upfront to work propery on the first
request. The same goes for any kind of remaining decorator.

4
docs/tutorial/css.rst

@ -1,3 +1,5 @@
.. _tutorial-css:
Step 7: Adding Style
====================
@ -25,3 +27,5 @@ folder we created before:
.flash { background: #CEE5F5; padding: 0.5em;
border: 1px solid #AACBE2; }
.error { background: #F0D6D6; padding: 0.5em; }
Continue with :ref:`tutorial-testing`.

4
docs/tutorial/dbcon.rst

@ -1,3 +1,5 @@
.. _tutorial-dbcon:
Step 4: Request Database Connections
------------------------------------
@ -31,3 +33,5 @@ request only and is available from within each function. Never store such
things on other objects because this would not work with threaded
environments. That special :data:`~flask.g` object does some magic behind
the scenes to ensure it does the right thing.
Continue to :ref:`tutorial-views`.

4
docs/tutorial/dbinit.rst

@ -1,3 +1,5 @@
.. _tutorial-dbinit:
Step 3: Creating The Database
=============================
@ -61,3 +63,5 @@ importing and calling that function::
If you get an exception later that a table cannot be found check that
you did call the `init_db` function and that your table names are
correct (singular vs. plural for example).
Continue with :ref:`tutorial-dbcon`

4
docs/tutorial/folders.rst

@ -1,3 +1,5 @@
.. _tutorial-folders:
Step 0: Creating The Folders
============================
@ -16,4 +18,6 @@ This is the place where css and javascript files go. Inside the
`templates` folder Flask will look for `Jinja2`_ templates. Drop all the
templates there.
Continue with :ref:`tutorial-schema`.
.. _Jinja2: http://jinja.pocoo.org/2/

4
docs/tutorial/introduction.rst

@ -1,3 +1,5 @@
.. _tutorial-introduction:
Introducing Flaskr
==================
@ -26,4 +28,6 @@ Here a screenshot from the final application:
:class: screenshot
:alt: screenshot of the final application
Continue with :ref:`tutorial-folders`.
.. _SQLAlchemy: http://www.sqlalchemy.org/

4
docs/tutorial/schema.rst

@ -1,3 +1,5 @@
.. _tutorial-schema:
Step 1: Database Schema
=======================
@ -19,3 +21,5 @@ This schema consists of a single table called `entries` and each row in
this table has an `id`, a `title` and a `text`. The `id` is an
automatically incrementing integer and a primary key, the other two are
strings that must not be null.
Continue with :ref:`tutorial-setup`.

4
docs/tutorial/setup.rst

@ -1,3 +1,5 @@
.. _tutorial-setup:
Step 2: Application Setup Code
==============================
@ -62,3 +64,5 @@ focus on that a little later. First we should get the database working.
Want your server to be publically available? Check out the
:ref:`externally visible server <public-server>` section for more
information.
Continue with :ref:`tutorial-dbinit`.

4
docs/tutorial/templates.rst

@ -1,3 +1,5 @@
.. _tutorial-templates:
Step 6: The Templates
=====================
@ -105,3 +107,5 @@ the user to login:
</dl>
</form>
{% endblock %}
Continue with :ref:`tutorial-css`.

2
docs/tutorial/testing.rst

@ -1,3 +1,5 @@
.. _tutorial-testing:
Bonus: Testing the Application
===============================

4
docs/tutorial/views.rst

@ -1,3 +1,5 @@
.. _tutorial-views:
Step 5: The View Functions
==========================
@ -85,3 +87,5 @@ that case if the user was logged in.
session.pop('logged_in', None)
flash('You were logged out')
return redirect(url_for('show_entries'))
Continue with :ref:`tutorial-templates`.

1
examples/minitwit/minitwit.py

@ -127,6 +127,7 @@ def user_timeline(username):
follower.who_id = ? and follower.whom_id = ?''',
[session['user_id'], profile_user['user_id']],
one=True) is not None
broken_just_for_djangocon
return render_template('timeline.html', messages=query_db('''
select message.*, user.* from message, user where
user.user_id = message.author_id and user.user_id = ?

Loading…
Cancel
Save