diff options
Diffstat (limited to 'app/static/doc/flask-docs/patterns')
22 files changed, 5008 insertions, 0 deletions
diff --git a/app/static/doc/flask-docs/patterns/appdispatch.html b/app/static/doc/flask-docs/patterns/appdispatch.html new file mode 100644 index 0000000..de88a7b --- /dev/null +++ b/app/static/doc/flask-docs/patterns/appdispatch.html @@ -0,0 +1,273 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Application Dispatching — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Using URL Processors" href="urlprocessors.html" /> + <link rel="prev" title="Application Factories" href="appfactories.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="urlprocessors.html" title="Using URL Processors" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="appfactories.html" title="Application Factories" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="application-dispatching"> +<span id="app-dispatch"></span><h1>Application Dispatching<a class="headerlink" href="#application-dispatching" title="Permalink to this headline">¶</a></h1> +<p>Application dispatching is the process of combining multiple Flask +applications on the WSGI level. You can not only combine Flask +applications into something larger but any WSGI application. This would +even allow you to run a Django and a Flask application in the same +interpreter side by side if you want. The usefulness of this depends on +how the applications work internally.</p> +<p>The fundamental difference from the <a class="reference internal" href="packages.html#larger-applications"><em>module approach</em></a> is that in this case you are running the same or +different Flask applications that are entirely isolated from each other. +They run different configurations and are dispatched on the WSGI level.</p> +<div class="section" id="working-with-this-document"> +<h2>Working with this Document<a class="headerlink" href="#working-with-this-document" title="Permalink to this headline">¶</a></h2> +<p>Each of the techniques and examples below results in an <tt class="docutils literal"><span class="pre">application</span></tt> object +that can be run with any WSGI server. For production, see <a class="reference internal" href="../deploying/index.html#deployment"><em>Deployment Options</em></a>. +For development, Werkzeug provides a builtin server for development available +at <a class="reference external" href="http://werkzeug.pocoo.org/docs/serving/#werkzeug.serving.run_simple" title="(in Werkzeug v0.7)"><tt class="xref py py-func docutils literal"><span class="pre">werkzeug.serving.run_simple()</span></tt></a>:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">werkzeug.serving</span> <span class="kn">import</span> <span class="n">run_simple</span> +<span class="n">run_simple</span><span class="p">(</span><span class="s">'localhost'</span><span class="p">,</span> <span class="mi">5000</span><span class="p">,</span> <span class="n">application</span><span class="p">,</span> <span class="n">use_reloader</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> +</pre></div> +</div> +<p>Note that <a class="reference external" href="http://werkzeug.pocoo.org/docs/serving/#werkzeug.serving.run_simple" title="(in Werkzeug v0.7)"><tt class="xref py py-func docutils literal"><span class="pre">run_simple</span></tt></a> is not intended for +use in production. Use a <a class="reference internal" href="../deploying/index.html#deployment"><em>full-blown WSGI server</em></a>.</p> +</div> +<div class="section" id="combining-applications"> +<h2>Combining Applications<a class="headerlink" href="#combining-applications" title="Permalink to this headline">¶</a></h2> +<p>If you have entirely separated applications and you want them to work next +to each other in the same Python interpreter process you can take +advantage of the <a class="reference external" href="http://werkzeug.pocoo.org/docs/middlewares/#werkzeug.wsgi.DispatcherMiddleware" title="(in Werkzeug v0.7)"><tt class="xref py py-class docutils literal"><span class="pre">werkzeug.wsgi.DispatcherMiddleware</span></tt></a>. The idea +here is that each Flask application is a valid WSGI application and they +are combined by the dispatcher middleware into a larger one that +dispatched based on prefix.</p> +<p>For example you could have your main application run on <cite>/</cite> and your +backend interface on <cite>/backend</cite>:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">werkzeug.wsgi</span> <span class="kn">import</span> <span class="n">DispatcherMiddleware</span> +<span class="kn">from</span> <span class="nn">frontend_app</span> <span class="kn">import</span> <span class="n">application</span> <span class="k">as</span> <span class="n">frontend</span> +<span class="kn">from</span> <span class="nn">backend_app</span> <span class="kn">import</span> <span class="n">application</span> <span class="k">as</span> <span class="n">backend</span> + +<span class="n">application</span> <span class="o">=</span> <span class="n">DispatcherMiddleware</span><span class="p">(</span><span class="n">frontend</span><span class="p">,</span> <span class="p">{</span> + <span class="s">'/backend'</span><span class="p">:</span> <span class="n">backend</span> +<span class="p">})</span> +</pre></div> +</div> +</div> +<div class="section" id="dispatch-by-subdomain"> +<h2>Dispatch by Subdomain<a class="headerlink" href="#dispatch-by-subdomain" title="Permalink to this headline">¶</a></h2> +<p>Sometimes you might want to use multiple instances of the same application +with different configurations. Assuming the application is created inside +a function and you can call that function to instanciate it, that is +really easy to implement. In order to develop your application to support +creating new instances in functions have a look at the +<a class="reference internal" href="appfactories.html#app-factories"><em>Application Factories</em></a> pattern.</p> +<p>A very common example would be creating applications per subdomain. For +instance you configure your webserver to dispatch all requests for all +subdomains to your application and you then use the subdomain information +to create user-specific instances. Once you have your server set up to +listen on all subdomains you can use a very simple WSGI application to do +the dynamic application creation.</p> +<p>The perfect level for abstraction in that regard is the WSGI layer. You +write your own WSGI application that looks at the request that comes and +and delegates it to your Flask application. If that application does not +exist yet, it is dynamically created and remembered:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="n">Lock</span> + +<span class="k">class</span> <span class="nc">SubdomainDispatcher</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> + + <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">domain</span><span class="p">,</span> <span class="n">create_app</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">domain</span> <span class="o">=</span> <span class="n">domain</span> + <span class="bp">self</span><span class="o">.</span><span class="n">create_app</span> <span class="o">=</span> <span class="n">create_app</span> + <span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">Lock</span><span class="p">()</span> + <span class="bp">self</span><span class="o">.</span><span class="n">instances</span> <span class="o">=</span> <span class="p">{}</span> + + <span class="k">def</span> <span class="nf">get_application</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">host</span><span class="p">):</span> + <span class="n">host</span> <span class="o">=</span> <span class="n">host</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">':'</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> + <span class="k">assert</span> <span class="n">host</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">domain</span><span class="p">),</span> <span class="s">'Configuration error'</span> + <span class="n">subdomain</span> <span class="o">=</span> <span class="n">host</span><span class="p">[:</span><span class="o">-</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">domain</span><span class="p">)]</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s">'.'</span><span class="p">)</span> + <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span> + <span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">subdomain</span><span class="p">)</span> + <span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> + <span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_app</span><span class="p">(</span><span class="n">subdomain</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="p">[</span><span class="n">subdomain</span><span class="p">]</span> <span class="o">=</span> <span class="n">app</span> + <span class="k">return</span> <span class="n">app</span> + + <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span> + <span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_application</span><span class="p">(</span><span class="n">environ</span><span class="p">[</span><span class="s">'HTTP_HOST'</span><span class="p">])</span> + <span class="k">return</span> <span class="n">app</span><span class="p">(</span><span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">)</span> +</pre></div> +</div> +<p>This dispatcher can then be used like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">myapplication</span> <span class="kn">import</span> <span class="n">create_app</span><span class="p">,</span> <span class="n">get_user_for_subdomain</span> +<span class="kn">from</span> <span class="nn">werkzeug.exceptions</span> <span class="kn">import</span> <span class="n">NotFound</span> + +<span class="k">def</span> <span class="nf">make_app</span><span class="p">(</span><span class="n">subdomain</span><span class="p">):</span> + <span class="n">user</span> <span class="o">=</span> <span class="n">get_user_for_subdomain</span><span class="p">(</span><span class="n">subdomain</span><span class="p">)</span> + <span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> + <span class="c"># if there is no user for that subdomain we still have</span> + <span class="c"># to return a WSGI application that handles that request.</span> + <span class="c"># We can then just return the NotFound() exception as</span> + <span class="c"># application which will render a default 404 page.</span> + <span class="c"># You might also redirect the user to the main page then</span> + <span class="k">return</span> <span class="n">NotFound</span><span class="p">()</span> + + <span class="c"># otherwise create the application for the specific user</span> + <span class="k">return</span> <span class="n">create_app</span><span class="p">(</span><span class="n">user</span><span class="p">)</span> + +<span class="n">application</span> <span class="o">=</span> <span class="n">SubdomainDispatcher</span><span class="p">(</span><span class="s">'example.com'</span><span class="p">,</span> <span class="n">make_app</span><span class="p">)</span> +</pre></div> +</div> +</div> +<div class="section" id="dispatch-by-path"> +<h2>Dispatch by Path<a class="headerlink" href="#dispatch-by-path" title="Permalink to this headline">¶</a></h2> +<p>Dispatching by a path on the URL is very similar. Instead of looking at +the <cite>Host</cite> header to figure out the subdomain one simply looks at the +request path up to the first slash:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">threading</span> <span class="kn">import</span> <span class="n">Lock</span> +<span class="kn">from</span> <span class="nn">werkzeug.wsgi</span> <span class="kn">import</span> <span class="n">pop_path_info</span><span class="p">,</span> <span class="n">peek_path_info</span> + +<span class="k">class</span> <span class="nc">PathDispatcher</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> + + <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">default_app</span><span class="p">,</span> <span class="n">create_app</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">default_app</span> <span class="o">=</span> <span class="n">default_app</span> + <span class="bp">self</span><span class="o">.</span><span class="n">create_app</span> <span class="o">=</span> <span class="n">create_app</span> + <span class="bp">self</span><span class="o">.</span><span class="n">lock</span> <span class="o">=</span> <span class="n">Lock</span><span class="p">()</span> + <span class="bp">self</span><span class="o">.</span><span class="n">instances</span> <span class="o">=</span> <span class="p">{}</span> + + <span class="k">def</span> <span class="nf">get_application</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">prefix</span><span class="p">):</span> + <span class="k">with</span> <span class="bp">self</span><span class="o">.</span><span class="n">lock</span><span class="p">:</span> + <span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">prefix</span><span class="p">)</span> + <span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> + <span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">create_app</span><span class="p">(</span><span class="n">prefix</span><span class="p">)</span> + <span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> + <span class="bp">self</span><span class="o">.</span><span class="n">instances</span><span class="p">[</span><span class="n">prefix</span><span class="p">]</span> <span class="o">=</span> <span class="n">app</span> + <span class="k">return</span> <span class="n">app</span> + + <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">):</span> + <span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_application</span><span class="p">(</span><span class="n">peek_path_info</span><span class="p">(</span><span class="n">environ</span><span class="p">))</span> + <span class="k">if</span> <span class="n">app</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> + <span class="n">pop_path_info</span><span class="p">(</span><span class="n">environ</span><span class="p">)</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">app</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">default_app</span> + <span class="k">return</span> <span class="n">app</span><span class="p">(</span><span class="n">environ</span><span class="p">,</span> <span class="n">start_response</span><span class="p">)</span> +</pre></div> +</div> +<p>The big difference between this and the subdomain one is that this one +falls back to another application if the creator function returns <cite>None</cite>:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">myapplication</span> <span class="kn">import</span> <span class="n">create_app</span><span class="p">,</span> <span class="n">default_app</span><span class="p">,</span> <span class="n">get_user_for_prefix</span> + +<span class="k">def</span> <span class="nf">make_app</span><span class="p">(</span><span class="n">prefix</span><span class="p">):</span> + <span class="n">user</span> <span class="o">=</span> <span class="n">get_user_for_prefix</span><span class="p">(</span><span class="n">prefix</span><span class="p">)</span> + <span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> + <span class="k">return</span> <span class="n">create_app</span><span class="p">(</span><span class="n">user</span><span class="p">)</span> + +<span class="n">application</span> <span class="o">=</span> <span class="n">PathDispatcher</span><span class="p">(</span><span class="n">default_app</span><span class="p">,</span> <span class="n">make_app</span><span class="p">)</span> +</pre></div> +</div> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Application Dispatching</a><ul> +<li><a class="reference internal" href="#working-with-this-document">Working with this Document</a></li> +<li><a class="reference internal" href="#combining-applications">Combining Applications</a></li> +<li><a class="reference internal" href="#dispatch-by-subdomain">Dispatch by Subdomain</a></li> +<li><a class="reference internal" href="#dispatch-by-path">Dispatch by Path</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="appfactories.html" title="previous chapter">Application Factories</a></li> + <li>Next: <a href="urlprocessors.html" title="next chapter">Using URL Processors</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/appdispatch.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/appfactories.html b/app/static/doc/flask-docs/patterns/appfactories.html new file mode 100644 index 0000000..ccd26e0 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/appfactories.html @@ -0,0 +1,186 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Application Factories — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Application Dispatching" href="appdispatch.html" /> + <link rel="prev" title="Larger Applications" href="packages.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="appdispatch.html" title="Application Dispatching" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="packages.html" title="Larger Applications" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="application-factories"> +<span id="app-factories"></span><h1>Application Factories<a class="headerlink" href="#application-factories" title="Permalink to this headline">¶</a></h1> +<p>If you are already using packages and blueprints for your application +(<a class="reference internal" href="../blueprints.html#blueprints"><em>Modular Applications with Blueprints</em></a>) there are a couple of really nice ways to further improve +the experience. A common pattern is creating the application object when +the blueprint is imported. But if you move the creation of this object, +into a function, you can then create multiple instances of this and later.</p> +<p>So why would you want to do this?</p> +<ol class="arabic simple"> +<li>Testing. You can have instances of the application with different +settings to test every case.</li> +<li>Multiple instances. Imagine you want to run different versions of the +same application. Of course you could have multiple instances with +different configs set up in your webserver, but if you use factories, +you can have multiple instances of the same application running in the +same application process which can be handy.</li> +</ol> +<p>So how would you then actually implement that?</p> +<div class="section" id="basic-factories"> +<h2>Basic Factories<a class="headerlink" href="#basic-factories" title="Permalink to this headline">¶</a></h2> +<p>The idea is to set up the application in a function. Like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">create_app</span><span class="p">(</span><span class="n">config_filename</span><span class="p">):</span> + <span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> + <span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">from_pyfile</span><span class="p">(</span><span class="n">config_filename</span><span class="p">)</span> + + <span class="kn">from</span> <span class="nn">yourapplication.views.admin</span> <span class="kn">import</span> <span class="n">admin</span> + <span class="kn">from</span> <span class="nn">yourapplication.views.frontend</span> <span class="kn">import</span> <span class="n">frontend</span> + <span class="n">app</span><span class="o">.</span><span class="n">register_blueprint</span><span class="p">(</span><span class="n">admin</span><span class="p">)</span> + <span class="n">app</span><span class="o">.</span><span class="n">register_blueprint</span><span class="p">(</span><span class="n">frontend</span><span class="p">)</span> + + <span class="k">return</span> <span class="n">app</span> +</pre></div> +</div> +<p>The downside is that you cannot use the application object in the blueprints +at import time. You can however use it from within a request. How do you +get access to the application with the config? Use +<a class="reference internal" href="../api.html#flask.current_app" title="flask.current_app"><tt class="xref py py-data docutils literal"><span class="pre">current_app</span></tt></a>:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">current_app</span><span class="p">,</span> <span class="n">Blueprint</span><span class="p">,</span> <span class="n">render_template</span> +<span class="n">admin</span> <span class="o">=</span> <span class="n">Blueprint</span><span class="p">(</span><span class="s">'admin'</span><span class="p">,</span> <span class="n">__name__</span><span class="p">,</span> <span class="n">url_prefix</span><span class="o">=</span><span class="s">'/admin'</span><span class="p">)</span> + +<span class="nd">@admin.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">index</span><span class="p">():</span> + <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="n">current_app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">'INDEX_TEMPLATE'</span><span class="p">])</span> +</pre></div> +</div> +<p>Here we look up the name of a template in the config.</p> +</div> +<div class="section" id="using-applications"> +<h2>Using Applications<a class="headerlink" href="#using-applications" title="Permalink to this headline">¶</a></h2> +<p>So to use such an application you then have to create the application +first. Here an example <cite>run.py</cite> file that runs such an application:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">yourapplication</span> <span class="kn">import</span> <span class="n">create_app</span> +<span class="n">app</span> <span class="o">=</span> <span class="n">create_app</span><span class="p">(</span><span class="s">'/path/to/config.cfg'</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">()</span> +</pre></div> +</div> +</div> +<div class="section" id="factory-improvements"> +<h2>Factory Improvements<a class="headerlink" href="#factory-improvements" title="Permalink to this headline">¶</a></h2> +<p>The factory function from above is not very clever so far, you can improve +it. The following changes are straightforward and possible:</p> +<ol class="arabic simple"> +<li>make it possible to pass in configuration values for unittests so that +you don’t have to create config files on the filesystem</li> +<li>call a function from a blueprint when the application is setting up so +that you have a place to modify attributes of the application (like +hooking in before / after request handlers etc.)</li> +<li>Add in WSGI middlewares when the application is creating if necessary.</li> +</ol> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Application Factories</a><ul> +<li><a class="reference internal" href="#basic-factories">Basic Factories</a></li> +<li><a class="reference internal" href="#using-applications">Using Applications</a></li> +<li><a class="reference internal" href="#factory-improvements">Factory Improvements</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="packages.html" title="previous chapter">Larger Applications</a></li> + <li>Next: <a href="appdispatch.html" title="next chapter">Application Dispatching</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/appfactories.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/caching.html b/app/static/doc/flask-docs/patterns/caching.html new file mode 100644 index 0000000..ed0d3c1 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/caching.html @@ -0,0 +1,178 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Caching — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="View Decorators" href="viewdecorators.html" /> + <link rel="prev" title="Uploading Files" href="fileuploads.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="viewdecorators.html" title="View Decorators" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="fileuploads.html" title="Uploading Files" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="caching"> +<span id="caching-pattern"></span><h1>Caching<a class="headerlink" href="#caching" title="Permalink to this headline">¶</a></h1> +<p>When your application runs slow, throw some caches in. Well, at least +it’s the easiest way to speed up things. What does a cache do? Say you +have a function that takes some time to complete but the results would +still be good enough if they were 5 minutes old. So then the idea is that +you actually put the result of that calculation into a cache for some +time.</p> +<p>Flask itself does not provide caching for you, but Werkzeug, one of the +libraries it is based on, has some very basic cache support. It supports +multiple cache backends, normally you want to use a memcached server.</p> +<div class="section" id="setting-up-a-cache"> +<h2>Setting up a Cache<a class="headerlink" href="#setting-up-a-cache" title="Permalink to this headline">¶</a></h2> +<p>You create a cache object once and keep it around, similar to how +<a class="reference internal" href="../api.html#flask.Flask" title="flask.Flask"><tt class="xref py py-class docutils literal"><span class="pre">Flask</span></tt></a> objects are created. If you are using the +development server you can create a +<a class="reference external" href="http://werkzeug.pocoo.org/docs/contrib/cache/#werkzeug.contrib.cache.SimpleCache" title="(in Werkzeug v0.7)"><tt class="xref py py-class docutils literal"><span class="pre">SimpleCache</span></tt></a> object, that one is a simple +cache that keeps the item stored in the memory of the Python interpreter:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">werkzeug.contrib.cache</span> <span class="kn">import</span> <span class="n">SimpleCache</span> +<span class="n">cache</span> <span class="o">=</span> <span class="n">SimpleCache</span><span class="p">()</span> +</pre></div> +</div> +<p>If you want to use memcached, make sure to have one of the memcache modules +supported (you get them from <a class="reference external" href="http://pypi.python.org/">PyPI</a>) and a +memcached server running somewhere. This is how you connect to such an +memcached server then:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">werkzeug.contrib.cache</span> <span class="kn">import</span> <span class="n">MemcachedCache</span> +<span class="n">cache</span> <span class="o">=</span> <span class="n">MemcachedCache</span><span class="p">([</span><span class="s">'127.0.0.1:11211'</span><span class="p">])</span> +</pre></div> +</div> +<p>If you are using App Engine, you can connect to the App Engine memcache +server easily:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">werkzeug.contrib.cache</span> <span class="kn">import</span> <span class="n">GAEMemcachedCache</span> +<span class="n">cache</span> <span class="o">=</span> <span class="n">GAEMemcachedCache</span><span class="p">()</span> +</pre></div> +</div> +</div> +<div class="section" id="using-a-cache"> +<h2>Using a Cache<a class="headerlink" href="#using-a-cache" title="Permalink to this headline">¶</a></h2> +<p>Now how can one use such a cache? There are two very important +operations: <a class="reference external" href="http://werkzeug.pocoo.org/docs/contrib/cache/#werkzeug.contrib.cache.BaseCache.get" title="(in Werkzeug v0.7)"><tt class="xref py py-meth docutils literal"><span class="pre">get()</span></tt></a> and +<a class="reference external" href="http://werkzeug.pocoo.org/docs/contrib/cache/#werkzeug.contrib.cache.BaseCache.set" title="(in Werkzeug v0.7)"><tt class="xref py py-meth docutils literal"><span class="pre">set()</span></tt></a>. This is how to use them:</p> +<p>To get an item from the cache call +<a class="reference external" href="http://werkzeug.pocoo.org/docs/contrib/cache/#werkzeug.contrib.cache.BaseCache.get" title="(in Werkzeug v0.7)"><tt class="xref py py-meth docutils literal"><span class="pre">get()</span></tt></a> with a string as key name. +If something is in the cache, it is returned. Otherwise that function +will return <cite>None</cite>:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="n">rv</span> <span class="o">=</span> <span class="n">cache</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'my-item'</span><span class="p">)</span> +</pre></div> +</div> +<p>To add items to the cache, use the <a class="reference external" href="http://werkzeug.pocoo.org/docs/contrib/cache/#werkzeug.contrib.cache.BaseCache.set" title="(in Werkzeug v0.7)"><tt class="xref py py-meth docutils literal"><span class="pre">set()</span></tt></a> +method instead. The first argument is the key and the second the value +that should be set. Also a timeout can be provided after which the cache +will automatically remove item.</p> +<p>Here a full example how this looks like normally:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">get_my_item</span><span class="p">():</span> + <span class="n">rv</span> <span class="o">=</span> <span class="n">cache</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'my-item'</span><span class="p">)</span> + <span class="k">if</span> <span class="n">rv</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> + <span class="n">rv</span> <span class="o">=</span> <span class="n">calculate_value</span><span class="p">()</span> + <span class="n">cache</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s">'my-item'</span><span class="p">,</span> <span class="n">rv</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">5</span> <span class="o">*</span> <span class="mi">60</span><span class="p">)</span> + <span class="k">return</span> <span class="n">rv</span> +</pre></div> +</div> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Caching</a><ul> +<li><a class="reference internal" href="#setting-up-a-cache">Setting up a Cache</a></li> +<li><a class="reference internal" href="#using-a-cache">Using a Cache</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="fileuploads.html" title="previous chapter">Uploading Files</a></li> + <li>Next: <a href="viewdecorators.html" title="next chapter">View Decorators</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/caching.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/deferredcallbacks.html b/app/static/doc/flask-docs/patterns/deferredcallbacks.html new file mode 100644 index 0000000..32b6b79 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/deferredcallbacks.html @@ -0,0 +1,180 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Deferred Request Callbacks — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Deployment Options" href="../deploying/index.html" /> + <link rel="prev" title="Streaming Contents" href="streaming.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="../deploying/index.html" title="Deployment Options" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="streaming.html" title="Streaming Contents" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="deferred-request-callbacks"> +<span id="deferred-callbacks"></span><h1>Deferred Request Callbacks<a class="headerlink" href="#deferred-request-callbacks" title="Permalink to this headline">¶</a></h1> +<p>One of the design principles of Flask is that response objects are created +and passed down a chain of potential callbacks that can modify them or +replace them. When the request handling starts, there is no response +object yet. It is created as necessary either by a view function or by +some other component in the system.</p> +<p>But what happens if you want to modify the response at a point where the +response does not exist yet? A common example for that would be a +before-request function that wants to set a cookie on the response object.</p> +<p>One way is to avoid the situation. Very often that is possible. For +instance you can try to move that logic into an after-request callback +instead. Sometimes however moving that code there is just not a very +pleasant experience or makes code look very awkward.</p> +<p>As an alternative possibility you can attach a bunch of callback functions +to the <a class="reference internal" href="../api.html#flask.g" title="flask.g"><tt class="xref py py-data docutils literal"><span class="pre">g</span></tt></a> object and call then at the end of the request. +This way you can defer code execution from anywhere in the application.</p> +<div class="section" id="the-decorator"> +<h2>The Decorator<a class="headerlink" href="#the-decorator" title="Permalink to this headline">¶</a></h2> +<p>The following decorator is the key. It registers a function on a list on +the <a class="reference internal" href="../api.html#flask.g" title="flask.g"><tt class="xref py py-data docutils literal"><span class="pre">g</span></tt></a> object:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">g</span> + +<span class="k">def</span> <span class="nf">after_this_request</span><span class="p">(</span><span class="n">f</span><span class="p">):</span> + <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="s">'after_request_callbacks'</span><span class="p">):</span> + <span class="n">g</span><span class="o">.</span><span class="n">after_request_callbacks</span> <span class="o">=</span> <span class="p">[]</span> + <span class="n">g</span><span class="o">.</span><span class="n">after_request_callbacks</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">f</span><span class="p">)</span> + <span class="k">return</span> <span class="n">f</span> +</pre></div> +</div> +</div> +<div class="section" id="calling-the-deferred"> +<h2>Calling the Deferred<a class="headerlink" href="#calling-the-deferred" title="Permalink to this headline">¶</a></h2> +<p>Now you can use the <cite>after_this_request</cite> decorator to mark a function to +be called at the end of the request. But we still need to call them. For +this the following function needs to be registered as +<a class="reference internal" href="../api.html#flask.Flask.after_request" title="flask.Flask.after_request"><tt class="xref py py-meth docutils literal"><span class="pre">after_request()</span></tt></a> callback:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="nd">@app.after_request</span> +<span class="k">def</span> <span class="nf">call_after_request_callbacks</span><span class="p">(</span><span class="n">response</span><span class="p">):</span> + <span class="k">for</span> <span class="n">callback</span> <span class="ow">in</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="s">'after_request_callbacks'</span><span class="p">,</span> <span class="p">()):</span> + <span class="n">response</span> <span class="o">=</span> <span class="n">callback</span><span class="p">(</span><span class="n">response</span><span class="p">)</span> + <span class="k">return</span> <span class="n">response</span> +</pre></div> +</div> +</div> +<div class="section" id="a-practical-example"> +<h2>A Practical Example<a class="headerlink" href="#a-practical-example" title="Permalink to this headline">¶</a></h2> +<p>Now we can easily at any point in time register a function to be called at +the end of this particular request. For example you can remember the +current language of the user in a cookie in the before-request function:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">request</span> + +<span class="nd">@app.before_request</span> +<span class="k">def</span> <span class="nf">detect_user_language</span><span class="p">():</span> + <span class="n">language</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">cookies</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'user_lang'</span><span class="p">)</span> + <span class="k">if</span> <span class="n">language</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> + <span class="n">language</span> <span class="o">=</span> <span class="n">guess_language_from_request</span><span class="p">()</span> + <span class="nd">@after_this_request</span> + <span class="k">def</span> <span class="nf">remember_language</span><span class="p">(</span><span class="n">response</span><span class="p">):</span> + <span class="n">response</span><span class="o">.</span><span class="n">set_cookie</span><span class="p">(</span><span class="s">'user_lang'</span><span class="p">,</span> <span class="n">language</span><span class="p">)</span> + <span class="n">g</span><span class="o">.</span><span class="n">language</span> <span class="o">=</span> <span class="n">language</span> +</pre></div> +</div> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Deferred Request Callbacks</a><ul> +<li><a class="reference internal" href="#the-decorator">The Decorator</a></li> +<li><a class="reference internal" href="#calling-the-deferred">Calling the Deferred</a></li> +<li><a class="reference internal" href="#a-practical-example">A Practical Example</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="streaming.html" title="previous chapter">Streaming Contents</a></li> + <li>Next: <a href="../deploying/index.html" title="next chapter">Deployment Options</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/deferredcallbacks.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/distribute.html b/app/static/doc/flask-docs/patterns/distribute.html new file mode 100644 index 0000000..8987a18 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/distribute.html @@ -0,0 +1,254 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Deploying with Distribute — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Deploying with Fabric" href="fabric.html" /> + <link rel="prev" title="Using URL Processors" href="urlprocessors.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="fabric.html" title="Deploying with Fabric" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="urlprocessors.html" title="Using URL Processors" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="deploying-with-distribute"> +<span id="distribute-deployment"></span><h1>Deploying with Distribute<a class="headerlink" href="#deploying-with-distribute" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="http://pypi.python.org/pypi/distribute">distribute</a>, formerly setuptools, is an extension library that is +commonly used to (like the name says) distribute Python libraries and +extensions. It extends distutils, a basic module installation system +shipped with Python to also support various more complex constructs that +make larger applications easier to distribute:</p> +<ul class="simple"> +<li><strong>support for dependencies</strong>: a library or application can declare a +list of other libraries it depends on which will be installed +automatically for you.</li> +<li><strong>package registry</strong>: setuptools registers your package with your +Python installation. This makes it possible to query information +provided by one package from another package. The best known feature of +this system is the entry point support which allows one package to +declare an “entry point” another package can hook into to extend the +other package.</li> +<li><strong>installation manager</strong>: <cite>easy_install</cite>, which comes with distribute +can install other libraries for you. You can also use <a class="reference external" href="http://pypi.python.org/pypi/pip">pip</a> which +sooner or later will replace <cite>easy_install</cite> which does more than just +installing packages for you.</li> +</ul> +<p>Flask itself, and all the libraries you can find on the cheeseshop +are distributed with either distribute, the older setuptools or distutils.</p> +<p>In this case we assume your application is called +<cite>yourapplication.py</cite> and you are not using a module, but a <a class="reference internal" href="packages.html#larger-applications"><em>package</em></a>. Distributing resources with standard modules is +not supported by <a class="reference external" href="http://pypi.python.org/pypi/distribute">distribute</a> so we will not bother with it. If you have +not yet converted your application into a package, head over to the +<a class="reference internal" href="packages.html#larger-applications"><em>Larger Applications</em></a> pattern to see how this can be done.</p> +<p>A working deployment with distribute is the first step into more complex +and more automated deployment scenarios. If you want to fully automate +the process, also read the <a class="reference internal" href="fabric.html#fabric-deployment"><em>Deploying with Fabric</em></a> chapter.</p> +<div class="section" id="basic-setup-script"> +<h2>Basic Setup Script<a class="headerlink" href="#basic-setup-script" title="Permalink to this headline">¶</a></h2> +<p>Because you have Flask running, you either have setuptools or distribute +available on your system anyways. If you do not, fear not, there is a +script to install it for you: <a class="reference external" href="http://python-distribute.org/distribute_setup.py">distribute_setup.py</a>. Just download and +run with your Python interpreter.</p> +<p>Standard disclaimer applies: <a class="reference internal" href="../installation.html#virtualenv"><em>you better use a virtualenv</em></a>.</p> +<p>Your setup code always goes into a file named <cite>setup.py</cite> next to your +application. The name of the file is only convention, but because +everybody will look for a file with that name, you better not change it.</p> +<p>Yes, even if you are using <cite>distribute</cite>, you are importing from a package +called <cite>setuptools</cite>. <cite>distribute</cite> is fully backwards compatible with +<cite>setuptools</cite>, so it also uses the same import name.</p> +<p>A basic <cite>setup.py</cite> file for a Flask application looks like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">setuptools</span> <span class="kn">import</span> <span class="n">setup</span> + +<span class="n">setup</span><span class="p">(</span> + <span class="n">name</span><span class="o">=</span><span class="s">'Your Application'</span><span class="p">,</span> + <span class="n">version</span><span class="o">=</span><span class="s">'1.0'</span><span class="p">,</span> + <span class="n">long_description</span><span class="o">=</span><span class="n">__doc__</span><span class="p">,</span> + <span class="n">packages</span><span class="o">=</span><span class="p">[</span><span class="s">'yourapplication'</span><span class="p">],</span> + <span class="n">include_package_data</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> + <span class="n">zip_safe</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> + <span class="n">install_requires</span><span class="o">=</span><span class="p">[</span><span class="s">'Flask'</span><span class="p">]</span> +<span class="p">)</span> +</pre></div> +</div> +<p>Please keep in mind that you have to list subpackages explicitly. If you +want distribute to lookup the packages for you automatically, you can use +the <cite>find_packages</cite> function:</p> +<div class="highlight-python"><pre>from setuptools import setup, find_packages + +setup( + ... + packages=find_packages() +)</pre> +</div> +<p>Most parameters to the <cite>setup</cite> function should be self explanatory, +<cite>include_package_data</cite> and <cite>zip_safe</cite> might not be. +<cite>include_package_data</cite> tells distribute to look for a <cite>MANIFEST.in</cite> file +and install all the entries that match as package data. We will use this +to distribute the static files and templates along with the Python module +(see <a class="reference internal" href="#distributing-resources"><em>Distributing Resources</em></a>). The <cite>zip_safe</cite> flag can be used to +force or prevent zip Archive creation. In general you probably don’t want +your packages to be installed as zip files because some tools do not +support them and they make debugging a lot harder.</p> +</div> +<div class="section" id="distributing-resources"> +<span id="id1"></span><h2>Distributing Resources<a class="headerlink" href="#distributing-resources" title="Permalink to this headline">¶</a></h2> +<p>If you try to install the package you just created, you will notice that +folders like <cite>static</cite> or <cite>templates</cite> are not installed for you. The +reason for this is that distribute does not know which files to add for +you. What you should do, is to create a <cite>MANIFEST.in</cite> file next to your +<cite>setup.py</cite> file. This file lists all the files that should be added to +your tarball:</p> +<div class="highlight-python"><pre>recursive-include yourapplication/templates * +recursive-include yourapplication/static *</pre> +</div> +<p>Don’t forget that even if you enlist them in your <cite>MANIFEST.in</cite> file, they +won’t be installed for you unless you set the <cite>include_package_data</cite> +parameter of the <cite>setup</cite> function to <cite>True</cite>!</p> +</div> +<div class="section" id="declaring-dependencies"> +<h2>Declaring Dependencies<a class="headerlink" href="#declaring-dependencies" title="Permalink to this headline">¶</a></h2> +<p>Dependencies are declared in the <cite>install_requires</cite> parameter as list. +Each item in that list is the name of a package that should be pulled from +PyPI on installation. By default it will always use the most recent +version, but you can also provide minimum and maximum version +requirements. Here some examples:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="n">install_requires</span><span class="o">=</span><span class="p">[</span> + <span class="s">'Flask>=0.2'</span><span class="p">,</span> + <span class="s">'SQLAlchemy>=0.6'</span><span class="p">,</span> + <span class="s">'BrokenPackage>=0.7,<=1.0'</span> +<span class="p">]</span> +</pre></div> +</div> +<p>I mentioned earlier that dependencies are pulled from PyPI. What if you +want to depend on a package that cannot be found on PyPI and won’t be +because it is an internal package you don’t want to share with anyone? +Just still do as if there was a PyPI entry for it and provide a list of +alternative locations where distribute should look for tarballs:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="n">dependency_links</span><span class="o">=</span><span class="p">[</span><span class="s">'http://example.com/yourfiles'</span><span class="p">]</span> +</pre></div> +</div> +<p>Make sure that page has a directory listing and the links on the page are +pointing to the actual tarballs with their correct filenames as this is +how distribute will find the files. If you have an internal company +server that contains the packages, provide the URL to that server there.</p> +</div> +<div class="section" id="installing-developing"> +<h2>Installing / Developing<a class="headerlink" href="#installing-developing" title="Permalink to this headline">¶</a></h2> +<p>To install your application (ideally into a virtualenv) just run the +<cite>setup.py</cite> script with the <cite>install</cite> parameter. It will install your +application into the virtualenv’s site-packages folder and also download +and install all dependencies:</p> +<div class="highlight-python"><pre>$ python setup.py install</pre> +</div> +<p>If you are developing on the package and also want the requirements to be +installed, you can use the <cite>develop</cite> command instead:</p> +<div class="highlight-python"><pre>$ python setup.py develop</pre> +</div> +<p>This has the advantage of just installing a link to the site-packages +folder instead of copying the data over. You can then continue to work on +the code without having to run <cite>install</cite> again after each change.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Deploying with Distribute</a><ul> +<li><a class="reference internal" href="#basic-setup-script">Basic Setup Script</a></li> +<li><a class="reference internal" href="#distributing-resources">Distributing Resources</a></li> +<li><a class="reference internal" href="#declaring-dependencies">Declaring Dependencies</a></li> +<li><a class="reference internal" href="#installing-developing">Installing / Developing</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="urlprocessors.html" title="previous chapter">Using URL Processors</a></li> + <li>Next: <a href="fabric.html" title="next chapter">Deploying with Fabric</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/distribute.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/errorpages.html b/app/static/doc/flask-docs/patterns/errorpages.html new file mode 100644 index 0000000..820e271 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/errorpages.html @@ -0,0 +1,182 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Custom Error Pages — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Lazily Loading Views" href="lazyloading.html" /> + <link rel="prev" title="AJAX with jQuery" href="jquery.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="lazyloading.html" title="Lazily Loading Views" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="jquery.html" title="AJAX with jQuery" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="custom-error-pages"> +<h1>Custom Error Pages<a class="headerlink" href="#custom-error-pages" title="Permalink to this headline">¶</a></h1> +<p>Flask comes with a handy <a class="reference internal" href="../api.html#flask.abort" title="flask.abort"><tt class="xref py py-func docutils literal"><span class="pre">abort()</span></tt></a> function that aborts a +request with an HTTP error code early. It will also provide a plain black +and white error page for you with a basic description, but nothing fancy.</p> +<p>Depending on the error code it is less or more likely for the user to +actually see such an error.</p> +<div class="section" id="common-error-codes"> +<h2>Common Error Codes<a class="headerlink" href="#common-error-codes" title="Permalink to this headline">¶</a></h2> +<p>The following error codes are some that are often displayed to the user, +even if the application behaves correctly:</p> +<dl class="docutils"> +<dt><em>404 Not Found</em></dt> +<dd>The good old “chap, you made a mistake typing that URL” message. So +common that even novices to the internet know that 404 means: damn, +the thing I was looking for is not there. It’s a very good idea to +make sure there is actually something useful on a 404 page, at least a +link back to the index.</dd> +<dt><em>403 Forbidden</em></dt> +<dd>If you have some kind of access control on your website, you will have +to send a 403 code for disallowed resources. So make sure the user +is not lost when they try to access a forbidden resource.</dd> +<dt><em>410 Gone</em></dt> +<dd>Did you know that there the “404 Not Found” has a brother named “410 +Gone”? Few people actually implement that, but the idea is that +resources that previously existed and got deleted answer with 410 +instead of 404. If you are not deleting documents permanently from +the database but just mark them as deleted, do the user a favour and +use the 410 code instead and display a message that what they were +looking for was deleted for all eternity.</dd> +<dt><em>500 Internal Server Error</em></dt> +<dd>Usually happens on programming errors or if the server is overloaded. +A terrible good idea to have a nice page there, because your +application <em>will</em> fail sooner or later (see also: +<a class="reference internal" href="../errorhandling.html#application-errors"><em>Handling Application Errors</em></a>).</dd> +</dl> +</div> +<div class="section" id="error-handlers"> +<h2>Error Handlers<a class="headerlink" href="#error-handlers" title="Permalink to this headline">¶</a></h2> +<p>An error handler is a function, just like a view function, but it is +called when an error happens and is passed that error. The error is most +likely a <a class="reference external" href="http://werkzeug.pocoo.org/docs/exceptions/#werkzeug.exceptions.HTTPException" title="(in Werkzeug v0.7)"><tt class="xref py py-exc docutils literal"><span class="pre">HTTPException</span></tt></a>, but in one case it +can be a different error: a handler for internal server errors will be +passed other exception instances as well if they are uncaught.</p> +<p>An error handler is registered with the <a class="reference internal" href="../api.html#flask.Flask.errorhandler" title="flask.Flask.errorhandler"><tt class="xref py py-meth docutils literal"><span class="pre">errorhandler()</span></tt></a> +decorator and the error code of the exception. Keep in mind that Flask +will <em>not</em> set the error code for you, so make sure to also provide the +HTTP status code when returning a response.</p> +<p>Here an example implementation for a “404 Page Not Found” exception:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">render_template</span> + +<span class="nd">@app.errorhandler</span><span class="p">(</span><span class="mi">404</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">page_not_found</span><span class="p">(</span><span class="n">e</span><span class="p">):</span> + <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">'404.html'</span><span class="p">),</span> <span class="mi">404</span> +</pre></div> +</div> +<p>An example template might be this:</p> +<div class="highlight-html+jinja"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"layout.html"</span> <span class="cp">%}</span> +<span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}</span>Page Not Found<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span> +<span class="cp">{%</span> <span class="k">block</span> <span class="nv">body</span> <span class="cp">%}</span> + <span class="nt"><h1></span>Page Not Found<span class="nt"></h1></span> + <span class="nt"><p></span>What you were looking for is just not there. + <span class="nt"><p><a</span> <span class="na">href=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">'index'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="nt">></span>go somewhere nice<span class="nt"></a></span> +<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span> +</pre></div> +</div> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Custom Error Pages</a><ul> +<li><a class="reference internal" href="#common-error-codes">Common Error Codes</a></li> +<li><a class="reference internal" href="#error-handlers">Error Handlers</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="jquery.html" title="previous chapter">AJAX with jQuery</a></li> + <li>Next: <a href="lazyloading.html" title="next chapter">Lazily Loading Views</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/errorpages.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/fabric.html b/app/static/doc/flask-docs/patterns/fabric.html new file mode 100644 index 0000000..9949480 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/fabric.html @@ -0,0 +1,298 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Deploying with Fabric — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Using SQLite 3 with Flask" href="sqlite3.html" /> + <link rel="prev" title="Deploying with Distribute" href="distribute.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="sqlite3.html" title="Using SQLite 3 with Flask" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="distribute.html" title="Deploying with Distribute" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="deploying-with-fabric"> +<span id="fabric-deployment"></span><h1>Deploying with Fabric<a class="headerlink" href="#deploying-with-fabric" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="http://fabfile.org/">Fabric</a> is a tool for Python similar to Makefiles but with the ability +to execute commands on a remote server. In combination with a properly +set up Python package (<a class="reference internal" href="packages.html#larger-applications"><em>Larger Applications</em></a>) and a good concept for +configurations (<a class="reference internal" href="../config.html#config"><em>Configuration Handling</em></a>) it is very easy to deploy Flask +applications to external servers.</p> +<p>Before we get started, here a quick checklist of things we have to ensure +upfront:</p> +<ul class="simple"> +<li>Fabric 1.0 has to be installed locally. This tutorial assumes the +latest version of Fabric.</li> +<li>The application already has to be a package and requires a working +<cite>setup.py</cite> file (<a class="reference internal" href="distribute.html#distribute-deployment"><em>Deploying with Distribute</em></a>).</li> +<li>In the following example we are using <cite>mod_wsgi</cite> for the remote +servers. You can of course use your own favourite server there, but +for this example we chose Apache + <cite>mod_wsgi</cite> because it’s very easy +to setup and has a simple way to reload applications without root +access.</li> +</ul> +<div class="section" id="creating-the-first-fabfile"> +<h2>Creating the first Fabfile<a class="headerlink" href="#creating-the-first-fabfile" title="Permalink to this headline">¶</a></h2> +<p>A fabfile is what controls what Fabric executes. It is named <cite>fabfile.py</cite> +and executed by the <cite>fab</cite> command. All the functions defined in that file +will show up as <cite>fab</cite> subcommands. They are executed on one or more +hosts. These hosts can be defined either in the fabfile or on the command +line. In this case we will add them to the fabfile.</p> +<p>This is a basic first example that has the ability to upload the current +sourcecode to the server and install it into a pre-existing +virtual environment:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">fabric.api</span> <span class="kn">import</span> <span class="o">*</span> + +<span class="c"># the user to use for the remote commands</span> +<span class="n">env</span><span class="o">.</span><span class="n">user</span> <span class="o">=</span> <span class="s">'appuser'</span> +<span class="c"># the servers where the commands are executed</span> +<span class="n">env</span><span class="o">.</span><span class="n">hosts</span> <span class="o">=</span> <span class="p">[</span><span class="s">'server1.example.com'</span><span class="p">,</span> <span class="s">'server2.example.com'</span><span class="p">]</span> + +<span class="k">def</span> <span class="nf">pack</span><span class="p">():</span> + <span class="c"># create a new source distribution as tarball</span> + <span class="n">local</span><span class="p">(</span><span class="s">'python setup.py sdist --formats=gztar'</span><span class="p">,</span> <span class="n">capture</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> + +<span class="k">def</span> <span class="nf">deploy</span><span class="p">():</span> + <span class="c"># figure out the release name and version</span> + <span class="n">dist</span> <span class="o">=</span> <span class="n">local</span><span class="p">(</span><span class="s">'python setup.py --fullname'</span><span class="p">,</span> <span class="n">capture</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span> + <span class="c"># upload the source tarball to the temporary folder on the server</span> + <span class="n">put</span><span class="p">(</span><span class="s">'dist/</span><span class="si">%s</span><span class="s">.tar.gz'</span> <span class="o">%</span> <span class="n">dist</span><span class="p">,</span> <span class="s">'/tmp/yourapplication.tar.gz'</span><span class="p">)</span> + <span class="c"># create a place where we can unzip the tarball, then enter</span> + <span class="c"># that directory and unzip it</span> + <span class="n">run</span><span class="p">(</span><span class="s">'mkdir /tmp/yourapplication'</span><span class="p">)</span> + <span class="k">with</span> <span class="n">cd</span><span class="p">(</span><span class="s">'/tmp/yourapplication'</span><span class="p">):</span> + <span class="n">run</span><span class="p">(</span><span class="s">'tar xzf /tmp/yourapplication.tar.gz'</span><span class="p">)</span> + <span class="c"># now setup the package with our virtual environment's</span> + <span class="c"># python interpreter</span> + <span class="n">run</span><span class="p">(</span><span class="s">'/var/www/yourapplication/env/bin/python setup.py install'</span><span class="p">)</span> + <span class="c"># now that all is set up, delete the folder again</span> + <span class="n">run</span><span class="p">(</span><span class="s">'rm -rf /tmp/yourapplication /tmp/yourapplication.tar.gz'</span><span class="p">)</span> + <span class="c"># and finally touch the .wsgi file so that mod_wsgi triggers</span> + <span class="c"># a reload of the application</span> + <span class="n">run</span><span class="p">(</span><span class="s">'touch /var/www/yourapplication.wsgi'</span><span class="p">)</span> +</pre></div> +</div> +<p>The example above is well documented and should be straightforward. Here +a recap of the most common commands fabric provides:</p> +<ul class="simple"> +<li><cite>run</cite> - executes a command on a remote server</li> +<li><cite>local</cite> - executes a command on the local machine</li> +<li><cite>put</cite> - uploads a file to the remote server</li> +<li><cite>cd</cite> - changes the directory on the serverside. This has to be used +in combination with the <cite>with</cite> statement.</li> +</ul> +</div> +<div class="section" id="running-fabfiles"> +<h2>Running Fabfiles<a class="headerlink" href="#running-fabfiles" title="Permalink to this headline">¶</a></h2> +<p>Now how do you execute that fabfile? You use the <cite>fab</cite> command. To +deploy the current version of the code on the remote server you would use +this command:</p> +<div class="highlight-python"><pre>$ fab pack deploy</pre> +</div> +<p>However this requires that our server already has the +<tt class="docutils literal"><span class="pre">/var/www/yourapplication</span></tt> folder created and +<tt class="docutils literal"><span class="pre">/var/www/yourapplication/env</span></tt> to be a virtual environment. Furthermore +are we not creating the configuration or <cite>.wsgi</cite> file on the server. So +how do we bootstrap a new server into our infrastructure?</p> +<p>This now depends on the number of servers we want to set up. If we just +have one application server (which the majority of applications will +have), creating a command in the fabfile for this is overkill. But +obviously you can do that. In that case you would probably call it +<cite>setup</cite> or <cite>bootstrap</cite> and then pass the servername explicitly on the +command line:</p> +<div class="highlight-python"><pre>$ fab -H newserver.example.com bootstrap</pre> +</div> +<p>To setup a new server you would roughly do these steps:</p> +<ol class="arabic"> +<li><p class="first">Create the directory structure in <tt class="docutils literal"><span class="pre">/var/www</span></tt>:</p> +<div class="highlight-python"><pre>$ mkdir /var/www/yourapplication +$ cd /var/www/yourapplication +$ virtualenv --distribute env</pre> +</div> +</li> +<li><p class="first">Upload a new <cite>application.wsgi</cite> file to the server and the +configuration file for the application (eg: <cite>application.cfg</cite>)</p> +</li> +<li><p class="first">Create a new Apache config for <cite>yourapplication</cite> and activate it. +Make sure to activate watching for changes of the <cite>.wsgi</cite> file so +that we can automatically reload the application by touching it. +(See <a class="reference internal" href="../deploying/mod_wsgi.html#mod-wsgi-deployment"><em>mod_wsgi (Apache)</em></a> for more information)</p> +</li> +</ol> +<p>So now the question is, where do the <cite>application.wsgi</cite> and +<cite>application.cfg</cite> files come from?</p> +</div> +<div class="section" id="the-wsgi-file"> +<h2>The WSGI File<a class="headerlink" href="#the-wsgi-file" title="Permalink to this headline">¶</a></h2> +<p>The WSGI file has to import the application and also to set an environment +variable so that the application knows where to look for the config. This +is a short example that does exactly that:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">os</span> +<span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s">'YOURAPPLICATION_CONFIG'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'/var/www/yourapplication/application.cfg'</span> +<span class="kn">from</span> <span class="nn">yourapplication</span> <span class="kn">import</span> <span class="n">app</span> +</pre></div> +</div> +<p>The application itself then has to initialize itself like this to look for +the config at that environment variable:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">from_object</span><span class="p">(</span><span class="s">'yourapplication.default_config'</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">from_envvar</span><span class="p">(</span><span class="s">'YOURAPPLICATION_CONFIG'</span><span class="p">)</span> +</pre></div> +</div> +<p>This approach is explained in detail in the <a class="reference internal" href="../config.html#config"><em>Configuration Handling</em></a> section of the +documentation.</p> +</div> +<div class="section" id="the-configuration-file"> +<h2>The Configuration File<a class="headerlink" href="#the-configuration-file" title="Permalink to this headline">¶</a></h2> +<p>Now as mentioned above, the application will find the correct +configuration file by looking up the <cite>YOURAPPLICATION_CONFIG</cite> environment +variable. So we have to put the configuration in a place where the +application will able to find it. Configuration files have the unfriendly +quality of being different on all computers, so you do not version them +usually.</p> +<p>A popular approach is to store configuration files for different servers +in a separate version control repository and check them out on all +servers. Then symlink the file that is active for the server into the +location where it’s expected (eg: <tt class="docutils literal"><span class="pre">/var/www/yourapplication</span></tt>).</p> +<p>Either way, in our case here we only expect one or two servers and we can +upload them ahead of time by hand.</p> +</div> +<div class="section" id="first-deployment"> +<h2>First Deployment<a class="headerlink" href="#first-deployment" title="Permalink to this headline">¶</a></h2> +<p>Now we can do our first deployment. We have set up the servers so that +they have their virtual environments and activated apache configs. Now we +can pack up the application and deploy it:</p> +<div class="highlight-python"><pre>$ fab pack deploy</pre> +</div> +<p>Fabric will now connect to all servers and run the commands as written +down in the fabfile. First it will execute pack so that we have our +tarball ready and then it will execute deploy and upload the source code +to all servers and install it there. Thanks to the <cite>setup.py</cite> file we +will automatically pull in the required libraries into our virtual +environment.</p> +</div> +<div class="section" id="next-steps"> +<h2>Next Steps<a class="headerlink" href="#next-steps" title="Permalink to this headline">¶</a></h2> +<p>From that point onwards there is so much that can be done to make +deployment actually fun:</p> +<ul class="simple"> +<li>Create a <cite>bootstrap</cite> command that initializes new servers. It could +initialize a new virtual environment, setup apache appropriately etc.</li> +<li>Put configuration files into a separate version control repository +and symlink the active configs into place.</li> +<li>You could also put your application code into a repository and check +out the latest version on the server and then install. That way you +can also easily go back to older versions.</li> +<li>hook in testing functionality so that you can deploy to an external +server and run the testsuite.</li> +</ul> +<p>Working with Fabric is fun and you will notice that it’s quite magical to +type <tt class="docutils literal"><span class="pre">fab</span> <span class="pre">deploy</span></tt> and see your application being deployed automatically +to one or more remote servers.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Deploying with Fabric</a><ul> +<li><a class="reference internal" href="#creating-the-first-fabfile">Creating the first Fabfile</a></li> +<li><a class="reference internal" href="#running-fabfiles">Running Fabfiles</a></li> +<li><a class="reference internal" href="#the-wsgi-file">The WSGI File</a></li> +<li><a class="reference internal" href="#the-configuration-file">The Configuration File</a></li> +<li><a class="reference internal" href="#first-deployment">First Deployment</a></li> +<li><a class="reference internal" href="#next-steps">Next Steps</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="distribute.html" title="previous chapter">Deploying with Distribute</a></li> + <li>Next: <a href="sqlite3.html" title="next chapter">Using SQLite 3 with Flask</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/fabric.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/favicon.html b/app/static/doc/flask-docs/patterns/favicon.html new file mode 100644 index 0000000..55c7ba7 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/favicon.html @@ -0,0 +1,162 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Adding a favicon — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Streaming Contents" href="streaming.html" /> + <link rel="prev" title="MongoKit in Flask" href="mongokit.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="streaming.html" title="Streaming Contents" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="mongokit.html" title="MongoKit in Flask" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="adding-a-favicon"> +<h1>Adding a favicon<a class="headerlink" href="#adding-a-favicon" title="Permalink to this headline">¶</a></h1> +<p>A “favicon” is an icon used by browsers for tabs and bookmarks. This helps +to distinguish your website and to give it a unique brand.</p> +<p>A common question is how to add a favicon to a flask application. First, of +course, you need an icon. It should be 16 × 16 pixels and in the ICO file +format. This is not a requirement but a de-facto standard supported by all +relevant browsers. Put the icon in your static directory as +<tt class="file docutils literal"><span class="pre">favicon.ico</span></tt>.</p> +<p>Now, to get browsers to find your icon, the correct way is to add a link +tag in your HTML. So, for example:</p> +<div class="highlight-html+jinja"><div class="highlight"><pre><span class="nt"><link</span> <span class="na">rel=</span><span class="s">"shortcut icon"</span> <span class="na">href=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">'static'</span><span class="o">,</span> <span class="nv">filename</span><span class="o">=</span><span class="s1">'favicon.ico'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="nt">></span> +</pre></div> +</div> +<p>That’s all you need for most browsers, however some really old ones do not +support this standard. The old de-facto standard is to serve this file, +with this name, at the website root. If your application is not mounted at +the root path of the domain you either need to configure the webserver to +serve the icon at the root or if you can’t do that you’re out of luck. If +however your application is the root you can simply route a redirect:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s">'/favicon.ico'</span><span class="p">,</span> + <span class="n">redirect_to</span><span class="o">=</span><span class="n">url_for</span><span class="p">(</span><span class="s">'static'</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="s">'favicon.ico'</span><span class="p">))</span> +</pre></div> +</div> +<p>If you want to save the extra redirect request you can also write a view +using <a class="reference internal" href="../api.html#flask.send_from_directory" title="flask.send_from_directory"><tt class="xref py py-func docutils literal"><span class="pre">send_from_directory()</span></tt></a>:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">os</span> +<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">send_from_directory</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/favicon.ico'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">favicon</span><span class="p">():</span> + <span class="k">return</span> <span class="n">send_from_directory</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">root_path</span><span class="p">,</span> <span class="s">'static'</span><span class="p">),</span> + <span class="s">'favicon.ico'</span><span class="p">,</span> <span class="n">mimetype</span><span class="o">=</span><span class="s">'image/vnd.microsoft.icon'</span><span class="p">)</span> +</pre></div> +</div> +<p>We can leave out the explicit mimetype and it will be guessed, but we may +as well specify it to avoid the extra guessing, as it will always be the +same.</p> +<p>The above will serve the icon via your application and if possible it’s +better to configure your dedicated web server to serve it; refer to the +webserver’s documentation.</p> +<div class="section" id="see-also"> +<h2>See also<a class="headerlink" href="#see-also" title="Permalink to this headline">¶</a></h2> +<ul class="simple"> +<li>The <a class="reference external" href="http://en.wikipedia.org/wiki/Favicon">Favicon</a> article on +Wikipedia</li> +</ul> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Adding a favicon</a><ul> +<li><a class="reference internal" href="#see-also">See also</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="mongokit.html" title="previous chapter">MongoKit in Flask</a></li> + <li>Next: <a href="streaming.html" title="next chapter">Streaming Contents</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/favicon.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/fileuploads.html b/app/static/doc/flask-docs/patterns/fileuploads.html new file mode 100644 index 0000000..2941367 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/fileuploads.html @@ -0,0 +1,283 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Uploading Files — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Caching" href="caching.html" /> + <link rel="prev" title="SQLAlchemy in Flask" href="sqlalchemy.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="caching.html" title="Caching" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="sqlalchemy.html" title="SQLAlchemy in Flask" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="uploading-files"> +<span id="id1"></span><h1>Uploading Files<a class="headerlink" href="#uploading-files" title="Permalink to this headline">¶</a></h1> +<p>Ah yes, the good old problem of file uploads. The basic idea of file +uploads is actually quite simple. It basically works like this:</p> +<ol class="arabic simple"> +<li>A <tt class="docutils literal"><span class="pre"><form></span></tt> tag is marked with <tt class="docutils literal"><span class="pre">enctype=multipart/form-data</span></tt> +and an <tt class="docutils literal"><span class="pre"><input</span> <span class="pre">type=file></span></tt> is placed in that form.</li> +<li>The application accesses the file from the <tt class="xref py py-attr docutils literal"><span class="pre">files</span></tt> +dictionary on the request object.</li> +<li>use the <a class="reference external" href="http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.FileStorage.save" title="(in Werkzeug v0.7)"><tt class="xref py py-meth docutils literal"><span class="pre">save()</span></tt></a> method of the file to save +the file permanently somewhere on the filesystem.</li> +</ol> +<div class="section" id="a-gentle-introduction"> +<h2>A Gentle Introduction<a class="headerlink" href="#a-gentle-introduction" title="Permalink to this headline">¶</a></h2> +<p>Let’s start with a very basic application that uploads a file to a +specific upload folder and displays a file to the user. Let’s look at the +bootstrapping code for our application:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">os</span> +<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">redirect</span><span class="p">,</span> <span class="n">url_for</span> +<span class="kn">from</span> <span class="nn">werkzeug</span> <span class="kn">import</span> <span class="n">secure_filename</span> + +<span class="n">UPLOAD_FOLDER</span> <span class="o">=</span> <span class="s">'/path/to/the/uploads'</span> +<span class="n">ALLOWED_EXTENSIONS</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="s">'txt'</span><span class="p">,</span> <span class="s">'pdf'</span><span class="p">,</span> <span class="s">'png'</span><span class="p">,</span> <span class="s">'jpg'</span><span class="p">,</span> <span class="s">'jpeg'</span><span class="p">,</span> <span class="s">'gif'</span><span class="p">])</span> + +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">'UPLOAD_FOLDER'</span><span class="p">]</span> <span class="o">=</span> <span class="n">UPLOAD_FOLDER</span> +</pre></div> +</div> +<p>So first we need a couple of imports. Most should be straightforward, the +<tt class="xref py py-func docutils literal"><span class="pre">werkzeug.secure_filename()</span></tt> is explained a little bit later. The +<cite>UPLOAD_FOLDER</cite> is where we will store the uploaded files and the +<cite>ALLOWED_EXTENSIONS</cite> is the set of allowed file extensions. Then we add a +URL rule by hand to the application. Now usually we’re not doing that, so +why here? The reasons is that we want the webserver (or our development +server) to serve these files for us and so we only need a rule to generate +the URL to these files.</p> +<p>Why do we limit the extensions that are allowed? You probably don’t want +your users to be able to upload everything there if the server is directly +sending out the data to the client. That way you can make sure that users +are not able to upload HTML files that would cause XSS problems (see +<a class="reference internal" href="../security.html#xss"><em>Cross-Site Scripting (XSS)</em></a>). Also make sure to disallow <cite>.php</cite> files if the server +executes them, but who has PHP installed on his server, right? :)</p> +<p>Next the functions that check if an extension is valid and that uploads +the file and redirects the user to the URL for the uploaded file:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">allowed_file</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span> + <span class="k">return</span> <span class="s">'.'</span> <span class="ow">in</span> <span class="n">filename</span> <span class="ow">and</span> \ + <span class="n">filename</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="s">'.'</span><span class="p">,</span> <span class="mi">1</span><span class="p">)[</span><span class="mi">1</span><span class="p">]</span> <span class="ow">in</span> <span class="n">ALLOWED_EXTENSIONS</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s">'GET'</span><span class="p">,</span> <span class="s">'POST'</span><span class="p">])</span> +<span class="k">def</span> <span class="nf">upload_file</span><span class="p">():</span> + <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s">'POST'</span><span class="p">:</span> + <span class="nb">file</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">files</span><span class="p">[</span><span class="s">'file'</span><span class="p">]</span> + <span class="k">if</span> <span class="nb">file</span> <span class="ow">and</span> <span class="n">allowed_file</span><span class="p">(</span><span class="nb">file</span><span class="o">.</span><span class="n">filename</span><span class="p">):</span> + <span class="n">filename</span> <span class="o">=</span> <span class="n">secure_filename</span><span class="p">(</span><span class="nb">file</span><span class="o">.</span><span class="n">filename</span><span class="p">)</span> + <span class="nb">file</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">'UPLOAD_FOLDER'</span><span class="p">],</span> <span class="n">filename</span><span class="p">))</span> + <span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s">'uploaded_file'</span><span class="p">,</span> + <span class="n">filename</span><span class="o">=</span><span class="n">filename</span><span class="p">))</span> + <span class="k">return</span> <span class="s">'''</span> +<span class="s"> <!doctype html></span> +<span class="s"> <title>Upload new File</title></span> +<span class="s"> <h1>Upload new File</h1></span> +<span class="s"> <form action="" method=post enctype=multipart/form-data></span> +<span class="s"> <p><input type=file name=file></span> +<span class="s"> <input type=submit value=Upload></span> +<span class="s"> </form></span> +<span class="s"> '''</span> +</pre></div> +</div> +<p>So what does that <a class="reference external" href="http://werkzeug.pocoo.org/docs/utils/#werkzeug.utils.secure_filename" title="(in Werkzeug v0.7)"><tt class="xref py py-func docutils literal"><span class="pre">secure_filename()</span></tt></a> function actually do? +Now the problem is that there is that principle called “never trust user +input”. This is also true for the filename of an uploaded file. All +submitted form data can be forged, and filenames can be dangerous. For +the moment just remember: always use that function to secure a filename +before storing it directly on the filesystem.</p> +<div class="admonition-information-for-the-pros admonition "> +<p class="first admonition-title">Information for the Pros</p> +<p>So you’re interested in what that <a class="reference external" href="http://werkzeug.pocoo.org/docs/utils/#werkzeug.utils.secure_filename" title="(in Werkzeug v0.7)"><tt class="xref py py-func docutils literal"><span class="pre">secure_filename()</span></tt></a> +function does and what the problem is if you’re not using it? So just +imagine someone would send the following information as <cite>filename</cite> to +your application:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="n">filename</span> <span class="o">=</span> <span class="s">"../../../../home/username/.bashrc"</span> +</pre></div> +</div> +<p>Assuming the number of <tt class="docutils literal"><span class="pre">../</span></tt> is correct and you would join this with +the <cite>UPLOAD_FOLDER</cite> the user might have the ability to modify a file on +the server’s filesystem he or she should not modify. This does require some +knowledge about how the application looks like, but trust me, hackers +are patient :)</p> +<p>Now let’s look how that function works:</p> +<div class="last highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">secure_filename</span><span class="p">(</span><span class="s">'../../../../home/username/.bashrc'</span><span class="p">)</span> +<span class="go">'home_username_.bashrc'</span> +</pre></div> +</div> +</div> +<p>Now one last thing is missing: the serving of the uploaded files. As of +Flask 0.5 we can use a function that does that for us:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">send_from_directory</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/uploads/<filename>'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">uploaded_file</span><span class="p">(</span><span class="n">filename</span><span class="p">):</span> + <span class="k">return</span> <span class="n">send_from_directory</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">'UPLOAD_FOLDER'</span><span class="p">],</span> + <span class="n">filename</span><span class="p">)</span> +</pre></div> +</div> +<p>Alternatively you can register <cite>uploaded_file</cite> as <cite>build_only</cite> rule and +use the <a class="reference external" href="http://werkzeug.pocoo.org/docs/middlewares/#werkzeug.wsgi.SharedDataMiddleware" title="(in Werkzeug v0.7)"><tt class="xref py py-class docutils literal"><span class="pre">SharedDataMiddleware</span></tt></a>. This also works with +older versions of Flask:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">werkzeug</span> <span class="kn">import</span> <span class="n">SharedDataMiddleware</span> +<span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s">'/uploads/<filename>'</span><span class="p">,</span> <span class="s">'uploaded_file'</span><span class="p">,</span> + <span class="n">build_only</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">wsgi_app</span> <span class="o">=</span> <span class="n">SharedDataMiddleware</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">wsgi_app</span><span class="p">,</span> <span class="p">{</span> + <span class="s">'/uploads'</span><span class="p">:</span> <span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">'UPLOAD_FOLDER'</span><span class="p">]</span> +<span class="p">})</span> +</pre></div> +</div> +<p>If you now run the application everything should work as expected.</p> +</div> +<div class="section" id="improving-uploads"> +<h2>Improving Uploads<a class="headerlink" href="#improving-uploads" title="Permalink to this headline">¶</a></h2> +<p class="versionadded"> +<span class="versionmodified">New in version 0.6.</span></p> +<p>So how exactly does Flask handle uploads? Well it will store them in the +webserver’s memory if the files are reasonable small otherwise in a +temporary location (as returned by <a class="reference external" href="http://docs.python.org/dev/library/tempfile.html#tempfile.gettempdir" title="(in Python v3.3)"><tt class="xref py py-func docutils literal"><span class="pre">tempfile.gettempdir()</span></tt></a>). But how +do you specify the maximum file size after which an upload is aborted? By +default Flask will happily accept file uploads to an unlimited amount of +memory, but you can limit that by setting the <tt class="docutils literal"><span class="pre">MAX_CONTENT_LENGTH</span></tt> +config key:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">Request</span> + +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">'MAX_CONTENT_LENGTH'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">16</span> <span class="o">*</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024</span> +</pre></div> +</div> +<p>The code above will limited the maximum allowed payload to 16 megabytes. +If a larger file is transmitted, Flask will raise an +<a class="reference external" href="http://werkzeug.pocoo.org/docs/exceptions/#werkzeug.exceptions.RequestEntityTooLarge" title="(in Werkzeug v0.7)"><tt class="xref py py-exc docutils literal"><span class="pre">RequestEntityTooLarge</span></tt></a> exception.</p> +<p>This feature was added in Flask 0.6 but can be achieved in older versions +as well by subclassing the request object. For more information on that +consult the Werkzeug documentation on file handling.</p> +</div> +<div class="section" id="upload-progress-bars"> +<h2>Upload Progress Bars<a class="headerlink" href="#upload-progress-bars" title="Permalink to this headline">¶</a></h2> +<p>A while ago many developers had the idea to read the incoming file in +small chunks and store the upload progress in the database to be able to +poll the progress with JavaScript from the client. Long story short: the +client asks the server every 5 seconds how much it has transmitted +already. Do you realize the irony? The client is asking for something it +should already know.</p> +<p>Now there are better solutions to that work faster and more reliable. The +web changed a lot lately and you can use HTML5, Java, Silverlight or Flash +to get a nicer uploading experience on the client side. Look at the +following libraries for some nice examples how to do that:</p> +<ul class="simple"> +<li><a class="reference external" href="http://www.plupload.com/">Plupload</a> - HTML5, Java, Flash</li> +<li><a class="reference external" href="http://www.swfupload.org/">SWFUpload</a> - Flash</li> +<li><a class="reference external" href="http://jumploader.com/">JumpLoader</a> - Java</li> +</ul> +</div> +<div class="section" id="an-easier-solution"> +<h2>An Easier Solution<a class="headerlink" href="#an-easier-solution" title="Permalink to this headline">¶</a></h2> +<p>Because the common pattern for file uploads exists almost unchanged in all +applications dealing with uploads, there is a Flask extension called +<a class="reference external" href="http://packages.python.org/Flask-Uploads/">Flask-Uploads</a> that implements a full fledged upload mechanism with +white and blacklisting of extensions and more.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Uploading Files</a><ul> +<li><a class="reference internal" href="#a-gentle-introduction">A Gentle Introduction</a></li> +<li><a class="reference internal" href="#improving-uploads">Improving Uploads</a></li> +<li><a class="reference internal" href="#upload-progress-bars">Upload Progress Bars</a></li> +<li><a class="reference internal" href="#an-easier-solution">An Easier Solution</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="sqlalchemy.html" title="previous chapter">SQLAlchemy in Flask</a></li> + <li>Next: <a href="caching.html" title="next chapter">Caching</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/fileuploads.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/flashing.html b/app/static/doc/flask-docs/patterns/flashing.html new file mode 100644 index 0000000..b4f53c7 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/flashing.html @@ -0,0 +1,221 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Message Flashing — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="AJAX with jQuery" href="jquery.html" /> + <link rel="prev" title="Template Inheritance" href="templateinheritance.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="jquery.html" title="AJAX with jQuery" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="templateinheritance.html" title="Template Inheritance" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="message-flashing"> +<span id="message-flashing-pattern"></span><h1>Message Flashing<a class="headerlink" href="#message-flashing" title="Permalink to this headline">¶</a></h1> +<p>Good applications and user interfaces are all about feedback. If the user +does not get enough feedback they will probably end up hating the +application. Flask provides a really simple way to give feedback to a +user with the flashing system. The flashing system basically makes it +possible to record a message at the end of a request and access it next +request and only next request. This is usually combined with a layout +template that does this.</p> +<div class="section" id="simple-flashing"> +<h2>Simple Flashing<a class="headerlink" href="#simple-flashing" title="Permalink to this headline">¶</a></h2> +<p>So here is a full example:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">flash</span><span class="p">,</span> <span class="n">redirect</span><span class="p">,</span> <span class="n">url_for</span><span class="p">,</span> <span class="n">render_template</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">index</span><span class="p">():</span> + <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">'index.html'</span><span class="p">)</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/login'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s">'GET'</span><span class="p">,</span> <span class="s">'POST'</span><span class="p">])</span> +<span class="k">def</span> <span class="nf">login</span><span class="p">():</span> + <span class="n">error</span> <span class="o">=</span> <span class="bp">None</span> + <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s">'POST'</span><span class="p">:</span> + <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s">'username'</span><span class="p">]</span> <span class="o">!=</span> <span class="s">'admin'</span> <span class="ow">or</span> \ + <span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">[</span><span class="s">'password'</span><span class="p">]</span> <span class="o">!=</span> <span class="s">'secret'</span><span class="p">:</span> + <span class="n">error</span> <span class="o">=</span> <span class="s">'Invalid credentials'</span> + <span class="k">else</span><span class="p">:</span> + <span class="n">flash</span><span class="p">(</span><span class="s">'You were successfully logged in'</span><span class="p">)</span> + <span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s">'index'</span><span class="p">))</span> + <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">'login.html'</span><span class="p">,</span> <span class="n">error</span><span class="o">=</span><span class="n">error</span><span class="p">)</span> +</pre></div> +</div> +<p>And here the <tt class="docutils literal"><span class="pre">layout.html</span></tt> template which does the magic:</p> +<div class="highlight-html+jinja"><div class="highlight"><pre><span class="cp"><!doctype html></span> +<span class="nt"><title></span>My Application<span class="nt"></title></span> +<span class="cp">{%</span> <span class="k">with</span> <span class="nv">messages</span> <span class="o">=</span> <span class="nv">get_flashed_messages</span><span class="o">()</span> <span class="cp">%}</span> + <span class="cp">{%</span> <span class="k">if</span> <span class="nv">messages</span> <span class="cp">%}</span> + <span class="nt"><ul</span> <span class="na">class=</span><span class="s">flashes</span><span class="nt">></span> + <span class="cp">{%</span> <span class="k">for</span> <span class="nv">message</span> <span class="k">in</span> <span class="nv">messages</span> <span class="cp">%}</span> + <span class="nt"><li></span><span class="cp">{{</span> <span class="nv">message</span> <span class="cp">}}</span><span class="nt"></li></span> + <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span> + <span class="nt"></ul></span> + <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span> +<span class="cp">{%</span> <span class="k">endwith</span> <span class="cp">%}</span> +<span class="cp">{%</span> <span class="k">block</span> <span class="nv">body</span> <span class="cp">%}{%</span> <span class="k">endblock</span> <span class="cp">%}</span> +</pre></div> +</div> +<p>And here the index.html template:</p> +<div class="highlight-html+jinja"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"layout.html"</span> <span class="cp">%}</span> +<span class="cp">{%</span> <span class="k">block</span> <span class="nv">body</span> <span class="cp">%}</span> + <span class="nt"><h1></span>Overview<span class="nt"></h1></span> + <span class="nt"><p></span>Do you want to <span class="nt"><a</span> <span class="na">href=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">'login'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="nt">></span>log in?<span class="nt"></a></span> +<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span> +</pre></div> +</div> +<p>And of course the login template:</p> +<div class="highlight-html+jinja"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"layout.html"</span> <span class="cp">%}</span> +<span class="cp">{%</span> <span class="k">block</span> <span class="nv">body</span> <span class="cp">%}</span> + <span class="nt"><h1></span>Login<span class="nt"></h1></span> + <span class="cp">{%</span> <span class="k">if</span> <span class="nv">error</span> <span class="cp">%}</span> + <span class="nt"><p</span> <span class="na">class=</span><span class="s">error</span><span class="nt">><strong></span>Error:<span class="nt"></strong></span> <span class="cp">{{</span> <span class="nv">error</span> <span class="cp">}}</span> + <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span> + <span class="nt"><form</span> <span class="na">action=</span><span class="s">""</span> <span class="na">method=</span><span class="s">post</span><span class="nt">></span> + <span class="nt"><dl></span> + <span class="nt"><dt></span>Username: + <span class="nt"><dd><input</span> <span class="na">type=</span><span class="s">text</span> <span class="na">name=</span><span class="s">username</span> <span class="na">value=</span><span class="s">"</span><span class="cp">{{</span> + <span class="nv">request.form.username</span> <span class="cp">}}</span><span class="s">"</span><span class="nt">></span> + <span class="nt"><dt></span>Password: + <span class="nt"><dd><input</span> <span class="na">type=</span><span class="s">password</span> <span class="na">name=</span><span class="s">password</span><span class="nt">></span> + <span class="nt"></dl></span> + <span class="nt"><p><input</span> <span class="na">type=</span><span class="s">submit</span> <span class="na">value=</span><span class="s">Login</span><span class="nt">></span> + <span class="nt"></form></span> +<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span> +</pre></div> +</div> +</div> +<div class="section" id="flashing-with-categories"> +<h2>Flashing With Categories<a class="headerlink" href="#flashing-with-categories" title="Permalink to this headline">¶</a></h2> +<p class="versionadded"> +<span class="versionmodified">New in version 0.3.</span></p> +<p>It is also possible to provide categories when flashing a message. The +default category if nothing is provided is <tt class="docutils literal"><span class="pre">'message'</span></tt>. Alternative +categories can be used to give the user better feedback. For example +error messages could be displayed with a red background.</p> +<p>To flash a message with a different category, just use the second argument +to the <a class="reference internal" href="../api.html#flask.flash" title="flask.flash"><tt class="xref py py-func docutils literal"><span class="pre">flash()</span></tt></a> function:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="n">flash</span><span class="p">(</span><span class="s">u'Invalid password provided'</span><span class="p">,</span> <span class="s">'error'</span><span class="p">)</span> +</pre></div> +</div> +<p>Inside the template you then have to tell the +<a class="reference internal" href="../api.html#flask.get_flashed_messages" title="flask.get_flashed_messages"><tt class="xref py py-func docutils literal"><span class="pre">get_flashed_messages()</span></tt></a> function to also return the +categories. The loop looks slightly different in that situation then:</p> +<div class="highlight-html+jinja"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">with</span> <span class="nv">messages</span> <span class="o">=</span> <span class="nv">get_flashed_messages</span><span class="o">(</span><span class="nv">with_categories</span><span class="o">=</span><span class="kp">true</span><span class="o">)</span> <span class="cp">%}</span> + <span class="cp">{%</span> <span class="k">if</span> <span class="nv">messages</span> <span class="cp">%}</span> + <span class="nt"><ul</span> <span class="na">class=</span><span class="s">flashes</span><span class="nt">></span> + <span class="cp">{%</span> <span class="k">for</span> <span class="nv">category</span><span class="o">,</span> <span class="nv">message</span> <span class="k">in</span> <span class="nv">messages</span> <span class="cp">%}</span> + <span class="nt"><li</span> <span class="na">class=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">category</span> <span class="cp">}}</span><span class="s">"</span><span class="nt">></span><span class="cp">{{</span> <span class="nv">message</span> <span class="cp">}}</span><span class="nt"></li></span> + <span class="cp">{%</span> <span class="k">endfor</span> <span class="cp">%}</span> + <span class="nt"></ul></span> + <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span> +<span class="cp">{%</span> <span class="k">endwith</span> <span class="cp">%}</span> +</pre></div> +</div> +<p>This is just one example of how to render these flashed messages. One +might also use the category to add a prefix such as +<tt class="docutils literal"><span class="pre"><strong>Error:</strong></span></tt> to the message.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Message Flashing</a><ul> +<li><a class="reference internal" href="#simple-flashing">Simple Flashing</a></li> +<li><a class="reference internal" href="#flashing-with-categories">Flashing With Categories</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="templateinheritance.html" title="previous chapter">Template Inheritance</a></li> + <li>Next: <a href="jquery.html" title="next chapter">AJAX with jQuery</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/flashing.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/index.html b/app/static/doc/flask-docs/patterns/index.html new file mode 100644 index 0000000..8190785 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/index.html @@ -0,0 +1,240 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Patterns for Flask — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="next" title="Larger Applications" href="packages.html" /> + <link rel="prev" title="Working with the Shell" href="../shell.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="packages.html" title="Larger Applications" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="../shell.html" title="Working with the Shell" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="patterns-for-flask"> +<span id="patterns"></span><h1>Patterns for Flask<a class="headerlink" href="#patterns-for-flask" title="Permalink to this headline">¶</a></h1> +<p>Certain things are common enough that the chances are high you will find +them in most web applications. For example quite a lot of applications +are using relational databases and user authentication. In that case, +chances are they will open a database connection at the beginning of the +request and get the information of the currently logged in user. At the +end of the request, the database connection is closed again.</p> +<p>There are more user contributed snippets and patterns in the <a class="reference external" href="http://flask.pocoo.org/snippets/">Flask +Snippet Archives</a>.</p> +<div class="toctree-wrapper compound"> +<ul> +<li class="toctree-l1"><a class="reference internal" href="packages.html">Larger Applications</a><ul> +<li class="toctree-l2"><a class="reference internal" href="packages.html#simple-packages">Simple Packages</a></li> +<li class="toctree-l2"><a class="reference internal" href="packages.html#working-with-blueprints">Working with Blueprints</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="appfactories.html">Application Factories</a><ul> +<li class="toctree-l2"><a class="reference internal" href="appfactories.html#basic-factories">Basic Factories</a></li> +<li class="toctree-l2"><a class="reference internal" href="appfactories.html#using-applications">Using Applications</a></li> +<li class="toctree-l2"><a class="reference internal" href="appfactories.html#factory-improvements">Factory Improvements</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="appdispatch.html">Application Dispatching</a><ul> +<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#working-with-this-document">Working with this Document</a></li> +<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#combining-applications">Combining Applications</a></li> +<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#dispatch-by-subdomain">Dispatch by Subdomain</a></li> +<li class="toctree-l2"><a class="reference internal" href="appdispatch.html#dispatch-by-path">Dispatch by Path</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="urlprocessors.html">Using URL Processors</a><ul> +<li class="toctree-l2"><a class="reference internal" href="urlprocessors.html#internationalized-application-urls">Internationalized Application URLs</a></li> +<li class="toctree-l2"><a class="reference internal" href="urlprocessors.html#internationalized-blueprint-urls">Internationalized Blueprint URLs</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="distribute.html">Deploying with Distribute</a><ul> +<li class="toctree-l2"><a class="reference internal" href="distribute.html#basic-setup-script">Basic Setup Script</a></li> +<li class="toctree-l2"><a class="reference internal" href="distribute.html#distributing-resources">Distributing Resources</a></li> +<li class="toctree-l2"><a class="reference internal" href="distribute.html#declaring-dependencies">Declaring Dependencies</a></li> +<li class="toctree-l2"><a class="reference internal" href="distribute.html#installing-developing">Installing / Developing</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="fabric.html">Deploying with Fabric</a><ul> +<li class="toctree-l2"><a class="reference internal" href="fabric.html#creating-the-first-fabfile">Creating the first Fabfile</a></li> +<li class="toctree-l2"><a class="reference internal" href="fabric.html#running-fabfiles">Running Fabfiles</a></li> +<li class="toctree-l2"><a class="reference internal" href="fabric.html#the-wsgi-file">The WSGI File</a></li> +<li class="toctree-l2"><a class="reference internal" href="fabric.html#the-configuration-file">The Configuration File</a></li> +<li class="toctree-l2"><a class="reference internal" href="fabric.html#first-deployment">First Deployment</a></li> +<li class="toctree-l2"><a class="reference internal" href="fabric.html#next-steps">Next Steps</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="sqlite3.html">Using SQLite 3 with Flask</a><ul> +<li class="toctree-l2"><a class="reference internal" href="sqlite3.html#connect-on-demand">Connect on Demand</a></li> +<li class="toctree-l2"><a class="reference internal" href="sqlite3.html#easy-querying">Easy Querying</a></li> +<li class="toctree-l2"><a class="reference internal" href="sqlite3.html#initial-schemas">Initial Schemas</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="sqlalchemy.html">SQLAlchemy in Flask</a><ul> +<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#flask-sqlalchemy-extension">Flask-SQLAlchemy Extension</a></li> +<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#declarative">Declarative</a></li> +<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#manual-object-relational-mapping">Manual Object Relational Mapping</a></li> +<li class="toctree-l2"><a class="reference internal" href="sqlalchemy.html#sql-abstraction-layer">SQL Abstraction Layer</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="fileuploads.html">Uploading Files</a><ul> +<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#a-gentle-introduction">A Gentle Introduction</a></li> +<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#improving-uploads">Improving Uploads</a></li> +<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#upload-progress-bars">Upload Progress Bars</a></li> +<li class="toctree-l2"><a class="reference internal" href="fileuploads.html#an-easier-solution">An Easier Solution</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="caching.html">Caching</a><ul> +<li class="toctree-l2"><a class="reference internal" href="caching.html#setting-up-a-cache">Setting up a Cache</a></li> +<li class="toctree-l2"><a class="reference internal" href="caching.html#using-a-cache">Using a Cache</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="viewdecorators.html">View Decorators</a><ul> +<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#login-required-decorator">Login Required Decorator</a></li> +<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#caching-decorator">Caching Decorator</a></li> +<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#templating-decorator">Templating Decorator</a></li> +<li class="toctree-l2"><a class="reference internal" href="viewdecorators.html#endpoint-decorator">Endpoint Decorator</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="wtforms.html">Form Validation with WTForms</a><ul> +<li class="toctree-l2"><a class="reference internal" href="wtforms.html#the-forms">The Forms</a></li> +<li class="toctree-l2"><a class="reference internal" href="wtforms.html#in-the-view">In the View</a></li> +<li class="toctree-l2"><a class="reference internal" href="wtforms.html#forms-in-templates">Forms in Templates</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="templateinheritance.html">Template Inheritance</a><ul> +<li class="toctree-l2"><a class="reference internal" href="templateinheritance.html#base-template">Base Template</a></li> +<li class="toctree-l2"><a class="reference internal" href="templateinheritance.html#child-template">Child Template</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="flashing.html">Message Flashing</a><ul> +<li class="toctree-l2"><a class="reference internal" href="flashing.html#simple-flashing">Simple Flashing</a></li> +<li class="toctree-l2"><a class="reference internal" href="flashing.html#flashing-with-categories">Flashing With Categories</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="jquery.html">AJAX with jQuery</a><ul> +<li class="toctree-l2"><a class="reference internal" href="jquery.html#loading-jquery">Loading jQuery</a></li> +<li class="toctree-l2"><a class="reference internal" href="jquery.html#where-is-my-site">Where is My Site?</a></li> +<li class="toctree-l2"><a class="reference internal" href="jquery.html#json-view-functions">JSON View Functions</a></li> +<li class="toctree-l2"><a class="reference internal" href="jquery.html#the-html">The HTML</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="errorpages.html">Custom Error Pages</a><ul> +<li class="toctree-l2"><a class="reference internal" href="errorpages.html#common-error-codes">Common Error Codes</a></li> +<li class="toctree-l2"><a class="reference internal" href="errorpages.html#error-handlers">Error Handlers</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="lazyloading.html">Lazily Loading Views</a><ul> +<li class="toctree-l2"><a class="reference internal" href="lazyloading.html#converting-to-centralized-url-map">Converting to Centralized URL Map</a></li> +<li class="toctree-l2"><a class="reference internal" href="lazyloading.html#loading-late">Loading Late</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="mongokit.html">MongoKit in Flask</a><ul> +<li class="toctree-l2"><a class="reference internal" href="mongokit.html#declarative">Declarative</a></li> +<li class="toctree-l2"><a class="reference internal" href="mongokit.html#pymongo-compatibility-layer">PyMongo Compatibility Layer</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="favicon.html">Adding a favicon</a><ul> +<li class="toctree-l2"><a class="reference internal" href="favicon.html#see-also">See also</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="streaming.html">Streaming Contents</a><ul> +<li class="toctree-l2"><a class="reference internal" href="streaming.html#basic-usage">Basic Usage</a></li> +<li class="toctree-l2"><a class="reference internal" href="streaming.html#streaming-from-templates">Streaming from Templates</a></li> +</ul> +</li> +<li class="toctree-l1"><a class="reference internal" href="deferredcallbacks.html">Deferred Request Callbacks</a><ul> +<li class="toctree-l2"><a class="reference internal" href="deferredcallbacks.html#the-decorator">The Decorator</a></li> +<li class="toctree-l2"><a class="reference internal" href="deferredcallbacks.html#calling-the-deferred">Calling the Deferred</a></li> +<li class="toctree-l2"><a class="reference internal" href="deferredcallbacks.html#a-practical-example">A Practical Example</a></li> +</ul> +</li> +</ul> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p><h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li>Previous: <a href="../shell.html" title="previous chapter">Working with the Shell</a></li> + <li>Next: <a href="packages.html" title="next chapter">Larger Applications</a></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/index.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/jquery.html b/app/static/doc/flask-docs/patterns/jquery.html new file mode 100644 index 0000000..7d03623 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/jquery.html @@ -0,0 +1,261 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>AJAX with jQuery — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Custom Error Pages" href="errorpages.html" /> + <link rel="prev" title="Message Flashing" href="flashing.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="errorpages.html" title="Custom Error Pages" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="flashing.html" title="Message Flashing" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="ajax-with-jquery"> +<h1>AJAX with jQuery<a class="headerlink" href="#ajax-with-jquery" title="Permalink to this headline">¶</a></h1> +<p><a class="reference external" href="http://jquery.com/">jQuery</a> is a small JavaScript library commonly used to simplify working +with the DOM and JavaScript in general. It is the perfect tool to make +web applications more dynamic by exchanging JSON between server and +client.</p> +<p>JSON itself is a very lightweight transport format, very similar to how +Python primitives (numbers, strings, dicts and lists) look like which is +widely supported and very easy to parse. It became popular a few years +ago and quickly replaced XML as transport format in web applications.</p> +<p>If you have Python 2.6 JSON will work out of the box, in Python 2.5 you +will have to install the <a class="reference external" href="http://pypi.python.org/pypi/simplejson">simplejson</a> library from PyPI.</p> +<div class="section" id="loading-jquery"> +<h2>Loading jQuery<a class="headerlink" href="#loading-jquery" title="Permalink to this headline">¶</a></h2> +<p>In order to use jQuery, you have to download it first and place it in the +static folder of your application and then ensure it’s loaded. Ideally +you have a layout template that is used for all pages where you just have +to add a script statement to the bottom of your <cite><body></cite> to load jQuery:</p> +<div class="highlight-html"><div class="highlight"><pre><span class="nt"><script </span><span class="na">type=</span><span class="s">text/javascript</span> <span class="na">src=</span><span class="s">"{{</span> +<span class="s"> url_for('static', filename='jquery.js') }}"</span><span class="nt">></script></span> +</pre></div> +</div> +<p>Another method is using Google’s <a class="reference external" href="http://code.google.com/apis/ajaxlibs/documentation/">AJAX Libraries API</a> to load jQuery:</p> +<div class="highlight-html"><div class="highlight"><pre><span class="nt"><script </span><span class="na">src=</span><span class="s">"//ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.js"</span><span class="nt">></script></span> +<span class="nt"><script></span><span class="nb">window</span><span class="p">.</span><span class="nx">jQuery</span> <span class="o">||</span> <span class="nb">document</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="s1">'<script src="{{</span> +<span class="s1"> url_for('</span><span class="kr">static</span><span class="s1">', filename='</span><span class="nx">jquery</span><span class="p">.</span><span class="nx">js</span><span class="s1">') }}">\x3C/script>'</span><span class="p">)</span><span class="nt"></script></span> +</pre></div> +</div> +<p>In this case you have to put jQuery into your static folder as a fallback, but it will +first try to load it directly from Google. This has the advantage that your +website will probably load faster for users if they went to at least one +other website before using the same jQuery version from Google because it +will already be in the browser cache.</p> +</div> +<div class="section" id="where-is-my-site"> +<h2>Where is My Site?<a class="headerlink" href="#where-is-my-site" title="Permalink to this headline">¶</a></h2> +<p>Do you know where your application is? If you are developing the answer +is quite simple: it’s on localhost port something and directly on the root +of that server. But what if you later decide to move your application to +a different location? For example to <tt class="docutils literal"><span class="pre">http://example.com/myapp</span></tt>? On +the server side this never was a problem because we were using the handy +<a class="reference internal" href="../api.html#flask.url_for" title="flask.url_for"><tt class="xref py py-func docutils literal"><span class="pre">url_for()</span></tt></a> function that could answer that question for +us, but if we are using jQuery we should not hardcode the path to +the application but make that dynamic, so how can we do that?</p> +<p>A simple method would be to add a script tag to our page that sets a +global variable to the prefix to the root of the application. Something +like this:</p> +<div class="highlight-html+jinja"><div class="highlight"><pre><span class="nt"><script </span><span class="na">type=</span><span class="s">text/javascript</span><span class="nt">></span> + <span class="nx">$SCRIPT_ROOT</span> <span class="o">=</span> <span class="cp">{{</span> <span class="nv">request.script_root</span><span class="o">|</span><span class="nf">tojson</span><span class="o">|</span><span class="nf">safe</span> <span class="cp">}}</span><span class="p">;</span> +<span class="nt"></script></span> +</pre></div> +</div> +<p>The <tt class="docutils literal"><span class="pre">|safe</span></tt> is necessary so that Jinja does not escape the JSON encoded +string with HTML rules. Usually this would be necessary, but we are +inside a <cite>script</cite> block here where different rules apply.</p> +<div class="admonition-information-for-pros admonition "> +<p class="first admonition-title">Information for Pros</p> +<p class="last">In HTML the <cite>script</cite> tag is declared <cite>CDATA</cite> which means that entities +will not be parsed. Everything until <tt class="docutils literal"><span class="pre"></script></span></tt> is handled as script. +This also means that there must never be any <tt class="docutils literal"><span class="pre"></</span></tt> between the script +tags. <tt class="docutils literal"><span class="pre">|tojson</span></tt> is kind enough to do the right thing here and +escape slashes for you (<tt class="docutils literal"><span class="pre">{{</span> <span class="pre">"</script>"|tojson|safe</span> <span class="pre">}}</span></tt> is rendered as +<tt class="docutils literal"><span class="pre">"<\/script>"</span></tt>).</p> +</div> +</div> +<div class="section" id="json-view-functions"> +<h2>JSON View Functions<a class="headerlink" href="#json-view-functions" title="Permalink to this headline">¶</a></h2> +<p>Now let’s create a server side function that accepts two URL arguments of +numbers which should be added together and then sent back to the +application in a JSON object. This is a really ridiculous example and is +something you usually would do on the client side alone, but a simple +example that shows how you would use jQuery and Flask nonetheless:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">jsonify</span><span class="p">,</span> <span class="n">render_template</span><span class="p">,</span> <span class="n">request</span> +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/_add_numbers'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">add_numbers</span><span class="p">():</span> + <span class="n">a</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'a'</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> + <span class="n">b</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">'b'</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">type</span><span class="o">=</span><span class="nb">int</span><span class="p">)</span> + <span class="k">return</span> <span class="n">jsonify</span><span class="p">(</span><span class="n">result</span><span class="o">=</span><span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">)</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">index</span><span class="p">():</span> + <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">'index.html'</span><span class="p">)</span> +</pre></div> +</div> +<p>As you can see I also added an <cite>index</cite> method here that renders a +template. This template will load jQuery as above and have a little form +we can add two numbers and a link to trigger the function on the server +side.</p> +<p>Note that we are using the <a class="reference external" href="http://werkzeug.pocoo.org/docs/datastructures/#werkzeug.datastructures.MultiDict.get" title="(in Werkzeug v0.7)"><tt class="xref py py-meth docutils literal"><span class="pre">get()</span></tt></a> method here +which will never fail. If the key is missing a default value (here <tt class="docutils literal"><span class="pre">0</span></tt>) +is returned. Furthermore it can convert values to a specific type (like +in our case <cite>int</cite>). This is especially handy for code that is +triggered by a script (APIs, JavaScript etc.) because you don’t need +special error reporting in that case.</p> +</div> +<div class="section" id="the-html"> +<h2>The HTML<a class="headerlink" href="#the-html" title="Permalink to this headline">¶</a></h2> +<p>Your index.html template either has to extend a <cite>layout.html</cite> template with +jQuery loaded and the <cite>$SCRIPT_ROOT</cite> variable set, or do that on the top. +Here’s the HTML code needed for our little application (<cite>index.html</cite>). +Notice that we also drop the script directly into the HTML here. It is +usually a better idea to have that in a separate script file:</p> +<div class="highlight-html"><div class="highlight"><pre><span class="nt"><script </span><span class="na">type=</span><span class="s">text/javascript</span><span class="nt">></span> + <span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span> + <span class="nx">$</span><span class="p">(</span><span class="s1">'a#calculate'</span><span class="p">).</span><span class="nx">bind</span><span class="p">(</span><span class="s1">'click'</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span> + <span class="nx">$</span><span class="p">.</span><span class="nx">getJSON</span><span class="p">(</span><span class="nx">$SCRIPT_ROOT</span> <span class="o">+</span> <span class="s1">'/_add_numbers'</span><span class="p">,</span> <span class="p">{</span> + <span class="nx">a</span><span class="o">:</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'input[name="a"]'</span><span class="p">).</span><span class="nx">val</span><span class="p">(),</span> + <span class="nx">b</span><span class="o">:</span> <span class="nx">$</span><span class="p">(</span><span class="s1">'input[name="b"]'</span><span class="p">).</span><span class="nx">val</span><span class="p">()</span> + <span class="p">},</span> <span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span> + <span class="nx">$</span><span class="p">(</span><span class="s2">"#result"</span><span class="p">).</span><span class="nx">text</span><span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">result</span><span class="p">);</span> + <span class="p">});</span> + <span class="k">return</span> <span class="kc">false</span><span class="p">;</span> + <span class="p">});</span> + <span class="p">});</span> +<span class="nt"></script></span> +<span class="nt"><h1></span>jQuery Example<span class="nt"></h1></span> +<span class="nt"><p><input</span> <span class="na">type=</span><span class="s">text</span> <span class="na">size=</span><span class="s">5</span> <span class="na">name=</span><span class="s">a</span><span class="nt">></span> + + <span class="nt"><input</span> <span class="na">type=</span><span class="s">text</span> <span class="na">size=</span><span class="s">5</span> <span class="na">name=</span><span class="s">b</span><span class="nt">></span> = + <span class="nt"><span</span> <span class="na">id=</span><span class="s">result</span><span class="nt">></span>?<span class="nt"></span></span> +<span class="nt"><p><a</span> <span class="na">href=</span><span class="s">#</span> <span class="na">id=</span><span class="s">calculate</span><span class="nt">></span>calculate server side<span class="nt"></a></span> +</pre></div> +</div> +<p>I won’t got into detail here about how jQuery works, just a very quick +explanation of the little bit of code above:</p> +<ol class="arabic simple"> +<li><tt class="docutils literal"><span class="pre">$(function()</span> <span class="pre">{</span> <span class="pre">...</span> <span class="pre">})</span></tt> specifies code that should run once the +browser is done loading the basic parts of the page.</li> +<li><tt class="docutils literal"><span class="pre">$('selector')</span></tt> selects an element and lets you operate on it.</li> +<li><tt class="docutils literal"><span class="pre">element.bind('event',</span> <span class="pre">func)</span></tt> specifies a function that should run +when the user clicked on the element. If that function returns +<cite>false</cite>, the default behaviour will not kick in (in this case, navigate +to the <cite>#</cite> URL).</li> +<li><tt class="docutils literal"><span class="pre">$.getJSON(url,</span> <span class="pre">data,</span> <span class="pre">func)</span></tt> sends a <cite>GET</cite> request to <cite>url</cite> and will +send the contents of the <cite>data</cite> object as query parameters. Once the +data arrived, it will call the given function with the return value as +argument. Note that we can use the <cite>$SCRIPT_ROOT</cite> variable here that +we set earlier.</li> +</ol> +<p>If you don’t get the whole picture, download the <a class="reference external" href="http://github.com/mitsuhiko/flask/tree/master/examples/jqueryexample">sourcecode +for this example</a> +from github.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">AJAX with jQuery</a><ul> +<li><a class="reference internal" href="#loading-jquery">Loading jQuery</a></li> +<li><a class="reference internal" href="#where-is-my-site">Where is My Site?</a></li> +<li><a class="reference internal" href="#json-view-functions">JSON View Functions</a></li> +<li><a class="reference internal" href="#the-html">The HTML</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="flashing.html" title="previous chapter">Message Flashing</a></li> + <li>Next: <a href="errorpages.html" title="next chapter">Custom Error Pages</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/jquery.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/lazyloading.html b/app/static/doc/flask-docs/patterns/lazyloading.html new file mode 100644 index 0000000..982b86a --- /dev/null +++ b/app/static/doc/flask-docs/patterns/lazyloading.html @@ -0,0 +1,214 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Lazily Loading Views — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="MongoKit in Flask" href="mongokit.html" /> + <link rel="prev" title="Custom Error Pages" href="errorpages.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="mongokit.html" title="MongoKit in Flask" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="errorpages.html" title="Custom Error Pages" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="lazily-loading-views"> +<h1>Lazily Loading Views<a class="headerlink" href="#lazily-loading-views" title="Permalink to this headline">¶</a></h1> +<p>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.</p> +<p>This can be a problem if your application has to import quick. It might +have to do that on systems like Google’s App Engine or other systems. So +if you suddenly notice that your application outgrows this approach you +can fall back to a centralized URL mapping.</p> +<p>The system that enables having a central URL map is the +<a class="reference internal" href="../api.html#flask.Flask.add_url_rule" title="flask.Flask.add_url_rule"><tt class="xref py py-meth docutils literal"><span class="pre">add_url_rule()</span></tt></a> function. Instead of using decorators, +you have a file that sets up the application with all URLs.</p> +<div class="section" id="converting-to-centralized-url-map"> +<h2>Converting to Centralized URL Map<a class="headerlink" href="#converting-to-centralized-url-map" title="Permalink to this headline">¶</a></h2> +<p>Imagine the current application looks somewhat like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span> +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">index</span><span class="p">():</span> + <span class="k">pass</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/user/<username>'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">user</span><span class="p">(</span><span class="n">username</span><span class="p">):</span> + <span class="k">pass</span> +</pre></div> +</div> +<p>Then the centralized approach you would have one file with the views +(<cite>views.py</cite>) but without any decorator:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">index</span><span class="p">():</span> + <span class="k">pass</span> + +<span class="k">def</span> <span class="nf">user</span><span class="p">(</span><span class="n">username</span><span class="p">):</span> + <span class="k">pass</span> +</pre></div> +</div> +<p>And then a file that sets up an application which maps the functions to +URLs:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span> +<span class="kn">from</span> <span class="nn">yourapplication</span> <span class="kn">import</span> <span class="n">views</span> +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s">'/'</span><span class="p">,</span> <span class="n">view_func</span><span class="o">=</span><span class="n">views</span><span class="o">.</span><span class="n">index</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s">'/user/<username>'</span><span class="p">,</span> <span class="n">view_func</span><span class="o">=</span><span class="n">views</span><span class="o">.</span><span class="n">user</span><span class="p">)</span> +</pre></div> +</div> +</div> +<div class="section" id="loading-late"> +<h2>Loading Late<a class="headerlink" href="#loading-late" title="Permalink to this headline">¶</a></h2> +<p>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:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">werkzeug</span> <span class="kn">import</span> <span class="n">import_string</span><span class="p">,</span> <span class="n">cached_property</span> + +<span class="k">class</span> <span class="nc">LazyView</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> + + <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">import_name</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">__module__</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">__name__</span> <span class="o">=</span> <span class="n">import_name</span><span class="o">.</span><span class="n">rsplit</span><span class="p">(</span><span class="s">'.'</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> + <span class="bp">self</span><span class="o">.</span><span class="n">import_name</span> <span class="o">=</span> <span class="n">import_name</span> + + <span class="nd">@cached_property</span> + <span class="k">def</span> <span class="nf">view</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">return</span> <span class="n">import_string</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">import_name</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">__call__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> + <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">view</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> +</pre></div> +</div> +<p>What’s important here is is that <cite>__module__</cite> and <cite>__name__</cite> are properly +set. This is used by Flask internally to figure out how to name the +URL rules in case you don’t provide a name for the rule yourself.</p> +<p>Then you can define your central place to combine the views like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span> +<span class="kn">from</span> <span class="nn">yourapplication.helpers</span> <span class="kn">import</span> <span class="n">LazyView</span> +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s">'/'</span><span class="p">,</span> + <span class="n">view_func</span><span class="o">=</span><span class="n">LazyView</span><span class="p">(</span><span class="s">'yourapplication.views.index'</span><span class="p">))</span> +<span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="s">'/user/<username>'</span><span class="p">,</span> + <span class="n">view_func</span><span class="o">=</span><span class="n">LazyView</span><span class="p">(</span><span class="s">'yourapplication.views.user'</span><span class="p">))</span> +</pre></div> +</div> +<p>You can further optimize this in terms of amount of keystrokes needed to +write this by having a function that calls into +<a class="reference internal" href="../api.html#flask.Flask.add_url_rule" title="flask.Flask.add_url_rule"><tt class="xref py py-meth docutils literal"><span class="pre">add_url_rule()</span></tt></a> by prefixing a string with the project +name and a dot, and by wrapping <cite>view_func</cite> in a <cite>LazyView</cite> as needed:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">url</span><span class="p">(</span><span class="n">url_rule</span><span class="p">,</span> <span class="n">import_name</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span> + <span class="n">view</span> <span class="o">=</span> <span class="n">LazyView</span><span class="p">(</span><span class="s">'yourapplication.'</span> <span class="o">+</span> <span class="n">import_name</span><span class="p">)</span> + <span class="n">app</span><span class="o">.</span><span class="n">add_url_rule</span><span class="p">(</span><span class="n">url_rule</span><span class="p">,</span> <span class="n">view_func</span><span class="o">=</span><span class="n">view</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">)</span> + +<span class="n">url</span><span class="p">(</span><span class="s">'/'</span><span class="p">,</span> <span class="s">'views.index'</span><span class="p">)</span> +<span class="n">url</span><span class="p">(</span><span class="s">'/user/<username>'</span><span class="p">,</span> <span class="s">'views.user'</span><span class="p">)</span> +</pre></div> +</div> +<p>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 properly on the first +request. The same goes for any kind of remaining decorator.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Lazily Loading Views</a><ul> +<li><a class="reference internal" href="#converting-to-centralized-url-map">Converting to Centralized URL Map</a></li> +<li><a class="reference internal" href="#loading-late">Loading Late</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="errorpages.html" title="previous chapter">Custom Error Pages</a></li> + <li>Next: <a href="mongokit.html" title="next chapter">MongoKit in Flask</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/lazyloading.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/mongokit.html b/app/static/doc/flask-docs/patterns/mongokit.html new file mode 100644 index 0000000..fa851dc --- /dev/null +++ b/app/static/doc/flask-docs/patterns/mongokit.html @@ -0,0 +1,241 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>MongoKit in Flask — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Adding a favicon" href="favicon.html" /> + <link rel="prev" title="Lazily Loading Views" href="lazyloading.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="favicon.html" title="Adding a favicon" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="lazyloading.html" title="Lazily Loading Views" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="mongokit-in-flask"> +<h1>MongoKit in Flask<a class="headerlink" href="#mongokit-in-flask" title="Permalink to this headline">¶</a></h1> +<p>Using a document database rather than a full DBMS gets more common these days. +This pattern shows how to use MongoKit, a document mapper library, to +integrate with MongoDB.</p> +<p>This pattern requires a running MongoDB server and the MongoKit library +installed.</p> +<p>There are two very common ways to use MongoKit. I will outline each of them +here:</p> +<div class="section" id="declarative"> +<h2>Declarative<a class="headerlink" href="#declarative" title="Permalink to this headline">¶</a></h2> +<p>The default behaviour of MongoKit is the declarative one that is based on +common ideas from Django or the SQLAlchemy declarative extension.</p> +<p>Here an example <cite>app.py</cite> module for your application:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span> +<span class="kn">from</span> <span class="nn">mongokit</span> <span class="kn">import</span> <span class="n">Connection</span><span class="p">,</span> <span class="n">Document</span> + +<span class="c"># configuration</span> +<span class="n">MONGODB_HOST</span> <span class="o">=</span> <span class="s">'localhost'</span> +<span class="n">MONGODB_PORT</span> <span class="o">=</span> <span class="mi">27017</span> + +<span class="c"># create the little application object</span> +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="o">.</span><span class="n">from_object</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> + +<span class="c"># connect to the database</span> +<span class="n">connection</span> <span class="o">=</span> <span class="n">Connection</span><span class="p">(</span><span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">'MONGODB_HOST'</span><span class="p">],</span> + <span class="n">app</span><span class="o">.</span><span class="n">config</span><span class="p">[</span><span class="s">'MONGODB_PORT'</span><span class="p">])</span> +</pre></div> +</div> +<p>To define your models, just subclass the <cite>Document</cite> class that is imported +from MongoKit. If you’ve seen the SQLAlchemy pattern you may wonder why we do +not have a session and even do not define a <cite>init_db</cite> function here. On the +one hand, MongoKit does not have something like a session. This sometimes +makes it more to type but also makes it blazingly fast. On the other hand, +MongoDB is schemaless. This means you can modify the data structure from one +insert query to the next without any problem. MongoKit is just schemaless +too, but implements some validation to ensure data integrity.</p> +<p>Here is an example document (put this also into <cite>app.py</cite>, e.g.):</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">max_length</span><span class="p">(</span><span class="n">length</span><span class="p">):</span> + <span class="k">def</span> <span class="nf">validate</span><span class="p">(</span><span class="n">value</span><span class="p">):</span> + <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">value</span><span class="p">)</span> <span class="o"><=</span> <span class="n">length</span><span class="p">:</span> + <span class="k">return</span> <span class="bp">True</span> + <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s">'</span><span class="si">%s</span><span class="s"> must be at most </span><span class="si">%s</span><span class="s"> characters long'</span> <span class="o">%</span> <span class="n">length</span><span class="p">)</span> + <span class="k">return</span> <span class="n">validate</span> + +<span class="k">class</span> <span class="nc">User</span><span class="p">(</span><span class="n">Document</span><span class="p">):</span> + <span class="n">structure</span> <span class="o">=</span> <span class="p">{</span> + <span class="s">'name'</span><span class="p">:</span> <span class="nb">unicode</span><span class="p">,</span> + <span class="s">'email'</span><span class="p">:</span> <span class="nb">unicode</span><span class="p">,</span> + <span class="p">}</span> + <span class="n">validators</span> <span class="o">=</span> <span class="p">{</span> + <span class="s">'name'</span><span class="p">:</span> <span class="n">max_length</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span> + <span class="s">'email'</span><span class="p">:</span> <span class="n">max_length</span><span class="p">(</span><span class="mi">120</span><span class="p">)</span> + <span class="p">}</span> + <span class="n">use_dot_notation</span> <span class="o">=</span> <span class="bp">True</span> + <span class="k">def</span> <span class="nf">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">return</span> <span class="s">'<User </span><span class="si">%r</span><span class="s">>'</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span> + +<span class="c"># register the User document with our current connection</span> +<span class="n">connection</span><span class="o">.</span><span class="n">register</span><span class="p">([</span><span class="n">User</span><span class="p">])</span> +</pre></div> +</div> +<p>This example shows you how to define your schema (named structure), a +validator for the maximum character length and uses a special MongoKit feature +called <cite>use_dot_notation</cite>. Per default MongoKit behaves like a python +dictionary but with <cite>use_dot_notation</cite> set to <cite>True</cite> you can use your +documents like you use models in nearly any other ORM by using dots to +separate between attributes.</p> +<p>You can insert entries into the database like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">yourapplication.database</span> <span class="kn">import</span> <span class="n">connection</span> +<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">yourapplication.models</span> <span class="kn">import</span> <span class="n">User</span> +<span class="gp">>>> </span><span class="n">collection</span> <span class="o">=</span> <span class="n">connection</span><span class="p">[</span><span class="s">'test'</span><span class="p">]</span><span class="o">.</span><span class="n">users</span> +<span class="gp">>>> </span><span class="n">user</span> <span class="o">=</span> <span class="n">collection</span><span class="o">.</span><span class="n">User</span><span class="p">()</span> +<span class="gp">>>> </span><span class="n">user</span><span class="p">[</span><span class="s">'name'</span><span class="p">]</span> <span class="o">=</span> <span class="s">u'admin'</span> +<span class="gp">>>> </span><span class="n">user</span><span class="p">[</span><span class="s">'email'</span><span class="p">]</span> <span class="o">=</span> <span class="s">u'admin@localhost'</span> +<span class="gp">>>> </span><span class="n">user</span><span class="o">.</span><span class="n">save</span><span class="p">()</span> +</pre></div> +</div> +<p>Note that MongoKit is kinda strict with used column types, you must not use a +common <cite>str</cite> type for either <cite>name</cite> or <cite>email</cite> but unicode.</p> +<p>Querying is simple as well:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="nb">list</span><span class="p">(</span><span class="n">collection</span><span class="o">.</span><span class="n">User</span><span class="o">.</span><span class="n">find</span><span class="p">())</span> +<span class="go">[<User u'admin'>]</span> +<span class="gp">>>> </span><span class="n">collection</span><span class="o">.</span><span class="n">User</span><span class="o">.</span><span class="n">find_one</span><span class="p">({</span><span class="s">'name'</span><span class="p">:</span> <span class="s">u'admin'</span><span class="p">})</span> +<span class="go"><User u'admin'></span> +</pre></div> +</div> +</div> +<div class="section" id="pymongo-compatibility-layer"> +<h2>PyMongo Compatibility Layer<a class="headerlink" href="#pymongo-compatibility-layer" title="Permalink to this headline">¶</a></h2> +<p>If you just want to use PyMongo, you can do that with MongoKit as well. You +may use this process if you need the best performance to get. Note that this +example does not show how to couple it with Flask, see the above MongoKit code +for examples:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">MongoKit</span> <span class="kn">import</span> <span class="n">Connection</span> + +<span class="n">connection</span> <span class="o">=</span> <span class="n">Connection</span><span class="p">()</span> +</pre></div> +</div> +<p>To insert data you can use the <cite>insert</cite> method. We have to get a +collection first, this is somewhat the same as a table in the SQL world.</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">collection</span> <span class="o">=</span> <span class="n">connection</span><span class="p">[</span><span class="s">'test'</span><span class="p">]</span><span class="o">.</span><span class="n">users</span> +<span class="gp">>>> </span><span class="n">user</span> <span class="o">=</span> <span class="p">{</span><span class="s">'name'</span><span class="p">:</span> <span class="s">u'admin'</span><span class="p">,</span> <span class="s">'email'</span><span class="p">:</span> <span class="s">u'admin@localhost'</span><span class="p">}</span> +<span class="gp">>>> </span><span class="n">collection</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">user</span><span class="p">)</span> +</pre></div> +</div> +<p>print list(collection.find()) +print collection.find_one({‘name’: u’admin’})</p> +<p>MongoKit will automatically commit for us.</p> +<p>To query your database, you use the collection directly:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="nb">list</span><span class="p">(</span><span class="n">collection</span><span class="o">.</span><span class="n">find</span><span class="p">())</span> +<span class="go">[{u'_id': ObjectId('4c271729e13823182f000000'), u'name': u'admin', u'email': u'admin@localhost'}]</span> +<span class="gp">>>> </span><span class="n">collection</span><span class="o">.</span><span class="n">find_one</span><span class="p">({</span><span class="s">'name'</span><span class="p">:</span> <span class="s">u'admin'</span><span class="p">})</span> +<span class="go">{u'_id': ObjectId('4c271729e13823182f000000'), u'name': u'admin', u'email': u'admin@localhost'}</span> +</pre></div> +</div> +<p>These results are also dict-like objects:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">collection</span><span class="o">.</span><span class="n">find_one</span><span class="p">({</span><span class="s">'name'</span><span class="p">:</span> <span class="s">u'admin'</span><span class="p">})</span> +<span class="gp">>>> </span><span class="n">r</span><span class="p">[</span><span class="s">'email'</span><span class="p">]</span> +<span class="go">u'admin@localhost'</span> +</pre></div> +</div> +<p>For more information about MongoKit, head over to the +<a class="reference external" href="http://bytebucket.org/namlook/mongokit/">website</a>.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">MongoKit in Flask</a><ul> +<li><a class="reference internal" href="#declarative">Declarative</a></li> +<li><a class="reference internal" href="#pymongo-compatibility-layer">PyMongo Compatibility Layer</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="lazyloading.html" title="previous chapter">Lazily Loading Views</a></li> + <li>Next: <a href="favicon.html" title="next chapter">Adding a favicon</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/mongokit.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/packages.html b/app/static/doc/flask-docs/patterns/packages.html new file mode 100644 index 0000000..9704b14 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/packages.html @@ -0,0 +1,219 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Larger Applications — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Application Factories" href="appfactories.html" /> + <link rel="prev" title="Patterns for Flask" href="index.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="appfactories.html" title="Application Factories" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="index.html" title="Patterns for Flask" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="larger-applications"> +<span id="id1"></span><h1>Larger Applications<a class="headerlink" href="#larger-applications" title="Permalink to this headline">¶</a></h1> +<p>For larger applications it’s a good idea to use a package instead of a +module. That is quite simple. Imagine a small application looks like +this:</p> +<div class="highlight-python"><pre>/yourapplication + /yourapplication.py + /static + /style.css + /templates + layout.html + index.html + login.html + ...</pre> +</div> +<div class="section" id="simple-packages"> +<h2>Simple Packages<a class="headerlink" href="#simple-packages" title="Permalink to this headline">¶</a></h2> +<p>To convert that into a larger one, just create a new folder +<cite>yourapplication</cite> inside the existing one and move everything below it. +Then rename <cite>yourapplication.py</cite> to <cite>__init__.py</cite>. (Make sure to delete +all <cite>.pyc</cite> files first, otherwise things would most likely break)</p> +<p>You should then end up with something like that:</p> +<div class="highlight-python"><pre>/yourapplication + /yourapplication + /__init__.py + /static + /style.css + /templates + layout.html + index.html + login.html + ...</pre> +</div> +<p>But how do you run your application now? The naive <tt class="docutils literal"><span class="pre">python</span> +<span class="pre">yourapplication/__init__.py</span></tt> will not work. Let’s just say that Python +does not want modules in packages to be the startup file. But that is not +a big problem, just add a new file called <cite>runserver.py</cite> next to the inner +<cite>yourapplication</cite> folder with the following contents:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">yourapplication</span> <span class="kn">import</span> <span class="n">app</span> +<span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">(</span><span class="n">debug</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> +</pre></div> +</div> +<p>What did we gain from this? Now we can restructure the application a bit +into multiple modules. The only thing you have to remember is the +following quick checklist:</p> +<ol class="arabic simple"> +<li>the <cite>Flask</cite> application object creation has to be in the +<cite>__init__.py</cite> file. That way each module can import it safely and the +<cite>__name__</cite> variable will resolve to the correct package.</li> +<li>all the view functions (the ones with a <a class="reference internal" href="../api.html#flask.Flask.route" title="flask.Flask.route"><tt class="xref py py-meth docutils literal"><span class="pre">route()</span></tt></a> +decorator on top) have to be imported when in the <cite>__init__.py</cite> file. +Not the object itself, but the module it is in. Import the view module +<strong>after the application object is created</strong>.</li> +</ol> +<p>Here’s an example <cite>__init__.py</cite>:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span> +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> + +<span class="kn">import</span> <span class="nn">yourapplication.views</span> +</pre></div> +</div> +<p>And this is what <cite>views.py</cite> would look like:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">yourapplication</span> <span class="kn">import</span> <span class="n">app</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">index</span><span class="p">():</span> + <span class="k">return</span> <span class="s">'Hello World!'</span> +</pre></div> +</div> +<p>You should then end up with something like that:</p> +<div class="highlight-python"><pre>/yourapplication + /runserver.py + /yourapplication + /__init__.py + /views.py + /static + /style.css + /templates + layout.html + index.html + login.html + ...</pre> +</div> +<div class="admonition-circular-imports admonition "> +<p class="first admonition-title">Circular Imports</p> +<p>Every Python programmer hates them, and yet we just added some: +circular imports (That’s when two modules depend on each other. In this +case <cite>views.py</cite> depends on <cite>__init__.py</cite>). Be advised that this is a +bad idea in general but here it is actually fine. The reason for this is +that we are not actually using the views in <cite>__init__.py</cite> and just +ensuring the module is imported and we are doing that at the bottom of +the file.</p> +<p class="last">There are still some problems with that approach but if you want to use +decorators there is no way around that. Check out the +<a class="reference internal" href="../becomingbig.html#becomingbig"><em>Becoming Big</em></a> section for some inspiration how to deal with that.</p> +</div> +</div> +<div class="section" id="working-with-blueprints"> +<span id="working-with-modules"></span><h2>Working with Blueprints<a class="headerlink" href="#working-with-blueprints" title="Permalink to this headline">¶</a></h2> +<p>If you have larger applications it’s recommended to divide them into +smaller groups where each group is implemented with the help of a +blueprint. For a gentle introduction into this topic refer to the +<a class="reference internal" href="../blueprints.html#blueprints"><em>Modular Applications with Blueprints</em></a> chapter of the documentation.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Larger Applications</a><ul> +<li><a class="reference internal" href="#simple-packages">Simple Packages</a></li> +<li><a class="reference internal" href="#working-with-blueprints">Working with Blueprints</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="index.html" title="previous chapter">Patterns for Flask</a></li> + <li>Next: <a href="appfactories.html" title="next chapter">Application Factories</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/packages.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/sqlalchemy.html b/app/static/doc/flask-docs/patterns/sqlalchemy.html new file mode 100644 index 0000000..8fd4363 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/sqlalchemy.html @@ -0,0 +1,310 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>SQLAlchemy in Flask — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Uploading Files" href="fileuploads.html" /> + <link rel="prev" title="Using SQLite 3 with Flask" href="sqlite3.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="fileuploads.html" title="Uploading Files" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="sqlite3.html" title="Using SQLite 3 with Flask" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="sqlalchemy-in-flask"> +<span id="sqlalchemy-pattern"></span><h1>SQLAlchemy in Flask<a class="headerlink" href="#sqlalchemy-in-flask" title="Permalink to this headline">¶</a></h1> +<p>Many people prefer <a class="reference external" href="http://www.sqlalchemy.org/">SQLAlchemy</a> for database access. In this case it’s +encouraged to use a package instead of a module for your flask application +and drop the models into a separate module (<a class="reference internal" href="packages.html#larger-applications"><em>Larger Applications</em></a>). +While that is not necessary, it makes a lot of sense.</p> +<p>There are four very common ways to use SQLAlchemy. I will outline each +of them here:</p> +<div class="section" id="flask-sqlalchemy-extension"> +<h2>Flask-SQLAlchemy Extension<a class="headerlink" href="#flask-sqlalchemy-extension" title="Permalink to this headline">¶</a></h2> +<p>Because SQLAlchemy is a common database abstraction layer and object +relational mapper that requires a little bit of configuration effort, +there is a Flask extension that handles that for you. This is recommended +if you want to get started quickly.</p> +<p>You can download <a class="reference external" href="http://packages.python.org/Flask-SQLAlchemy/">Flask-SQLAlchemy</a> from <a class="reference external" href="http://pypi.python.org/pypi/Flask-SQLAlchemy">PyPI</a>.</p> +</div> +<div class="section" id="declarative"> +<h2>Declarative<a class="headerlink" href="#declarative" title="Permalink to this headline">¶</a></h2> +<p>The declarative extension in SQLAlchemy is the most recent method of using +SQLAlchemy. It allows you to define tables and models in one go, similar +to how Django works. In addition to the following text I recommend the +official documentation on the <a class="reference external" href="http://www.sqlalchemy.org/docs/orm/extensions/declarative.html">declarative</a> extension.</p> +<p>Here the example <cite>database.py</cite> module for your application:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">create_engine</span> +<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">scoped_session</span><span class="p">,</span> <span class="n">sessionmaker</span> +<span class="kn">from</span> <span class="nn">sqlalchemy.ext.declarative</span> <span class="kn">import</span> <span class="n">declarative_base</span> + +<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s">'sqlite:////tmp/test.db'</span><span class="p">,</span> <span class="n">convert_unicode</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> +<span class="n">db_session</span> <span class="o">=</span> <span class="n">scoped_session</span><span class="p">(</span><span class="n">sessionmaker</span><span class="p">(</span><span class="n">autocommit</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> + <span class="n">autoflush</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> + <span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">))</span> +<span class="n">Base</span> <span class="o">=</span> <span class="n">declarative_base</span><span class="p">()</span> +<span class="n">Base</span><span class="o">.</span><span class="n">query</span> <span class="o">=</span> <span class="n">db_session</span><span class="o">.</span><span class="n">query_property</span><span class="p">()</span> + +<span class="k">def</span> <span class="nf">init_db</span><span class="p">():</span> + <span class="c"># import all modules here that might define models so that</span> + <span class="c"># they will be registered properly on the metadata. Otherwise</span> + <span class="c"># you will have to import them first before calling init_db()</span> + <span class="kn">import</span> <span class="nn">yourapplication.models</span> + <span class="n">Base</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">create_all</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span> +</pre></div> +</div> +<p>To define your models, just subclass the <cite>Base</cite> class that was created by +the code above. If you are wondering why we don’t have to care about +threads here (like we did in the SQLite3 example above with the +<a class="reference internal" href="../api.html#flask.g" title="flask.g"><tt class="xref py py-data docutils literal"><span class="pre">g</span></tt></a> object): that’s because SQLAlchemy does that for us +already with the <tt class="xref py py-class docutils literal"><span class="pre">scoped_session</span></tt>.</p> +<p>To use SQLAlchemy in a declarative way with your application, you just +have to put the following code into your application module. Flask will +automatically remove database sessions at the end of the request for you:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">yourapplication.database</span> <span class="kn">import</span> <span class="n">db_session</span> + +<span class="nd">@app.teardown_request</span> +<span class="k">def</span> <span class="nf">shutdown_session</span><span class="p">(</span><span class="n">exception</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span> + <span class="n">db_session</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span> +</pre></div> +</div> +<p>Here is an example model (put this into <cite>models.py</cite>, e.g.):</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span> +<span class="kn">from</span> <span class="nn">yourapplication.database</span> <span class="kn">import</span> <span class="n">Base</span> + +<span class="k">class</span> <span class="nc">User</span><span class="p">(</span><span class="n">Base</span><span class="p">):</span> + <span class="n">__tablename__</span> <span class="o">=</span> <span class="s">'users'</span> + <span class="nb">id</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> + <span class="n">name</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> + <span class="n">email</span> <span class="o">=</span> <span class="n">Column</span><span class="p">(</span><span class="n">String</span><span class="p">(</span><span class="mi">120</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> + + <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span> + <span class="bp">self</span><span class="o">.</span><span class="n">email</span> <span class="o">=</span> <span class="n">email</span> + + <span class="k">def</span> <span class="nf">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">return</span> <span class="s">'<User </span><span class="si">%r</span><span class="s">>'</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">)</span> +</pre></div> +</div> +<p>To create the database you can use the <cite>init_db</cite> function:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">yourapplication.database</span> <span class="kn">import</span> <span class="n">init_db</span> +<span class="gp">>>> </span><span class="n">init_db</span><span class="p">()</span> +</pre></div> +</div> +<p>You can insert entries into the database like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">yourapplication.database</span> <span class="kn">import</span> <span class="n">db_session</span> +<span class="gp">>>> </span><span class="kn">from</span> <span class="nn">yourapplication.models</span> <span class="kn">import</span> <span class="n">User</span> +<span class="gp">>>> </span><span class="n">u</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span><span class="s">'admin'</span><span class="p">,</span> <span class="s">'admin@localhost'</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">db_session</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">u</span><span class="p">)</span> +<span class="gp">>>> </span><span class="n">db_session</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span> +</pre></div> +</div> +<p>Querying is simple as well:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">all</span><span class="p">()</span> +<span class="go">[<User u'admin'>]</span> +<span class="gp">>>> </span><span class="n">User</span><span class="o">.</span><span class="n">query</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">User</span><span class="o">.</span><span class="n">name</span> <span class="o">==</span> <span class="s">'admin'</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span> +<span class="go"><User u'admin'></span> +</pre></div> +</div> +</div> +<div class="section" id="manual-object-relational-mapping"> +<h2>Manual Object Relational Mapping<a class="headerlink" href="#manual-object-relational-mapping" title="Permalink to this headline">¶</a></h2> +<p>Manual object relational mapping has a few upsides and a few downsides +versus the declarative approach from above. The main difference is that +you define tables and classes separately and map them together. It’s more +flexible but a little more to type. In general it works like the +declarative approach, so make sure to also split up your application into +multiple modules in a package.</p> +<p>Here is an example <cite>database.py</cite> module for your application:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">create_engine</span><span class="p">,</span> <span class="n">MetaData</span> +<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">scoped_session</span><span class="p">,</span> <span class="n">sessionmaker</span> + +<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s">'sqlite:////tmp/test.db'</span><span class="p">,</span> <span class="n">convert_unicode</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> +<span class="n">metadata</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">()</span> +<span class="n">db_session</span> <span class="o">=</span> <span class="n">scoped_session</span><span class="p">(</span><span class="n">sessionmaker</span><span class="p">(</span><span class="n">autocommit</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> + <span class="n">autoflush</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> + <span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">))</span> +<span class="k">def</span> <span class="nf">init_db</span><span class="p">():</span> + <span class="n">metadata</span><span class="o">.</span><span class="n">create_all</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span> +</pre></div> +</div> +<p>As for the declarative approach you need to close the session after +each request. Put this into your application module:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">yourapplication.database</span> <span class="kn">import</span> <span class="n">db_session</span> + +<span class="nd">@app.teardown_request</span> +<span class="k">def</span> <span class="nf">shutdown_session</span><span class="p">(</span><span class="n">exception</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span> + <span class="n">db_session</span><span class="o">.</span><span class="n">remove</span><span class="p">()</span> +</pre></div> +</div> +<p>Here is an example table and model (put this into <cite>models.py</cite>):</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">Table</span><span class="p">,</span> <span class="n">Column</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">String</span> +<span class="kn">from</span> <span class="nn">sqlalchemy.orm</span> <span class="kn">import</span> <span class="n">mapper</span> +<span class="kn">from</span> <span class="nn">yourapplication.database</span> <span class="kn">import</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">db_session</span> + +<span class="k">class</span> <span class="nc">User</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span> + <span class="n">query</span> <span class="o">=</span> <span class="n">db_session</span><span class="o">.</span><span class="n">query_property</span><span class="p">()</span> + + <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span> + <span class="bp">self</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="n">name</span> + <span class="bp">self</span><span class="o">.</span><span class="n">email</span> <span class="o">=</span> <span class="n">email</span> + + <span class="k">def</span> <span class="nf">__repr__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> + <span class="k">return</span> <span class="s">'<User </span><span class="si">%r</span><span class="s">>'</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">email</span><span class="p">)</span> + +<span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s">'users'</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> + <span class="n">Column</span><span class="p">(</span><span class="s">'id'</span><span class="p">,</span> <span class="n">Integer</span><span class="p">,</span> <span class="n">primary_key</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> + <span class="n">Column</span><span class="p">(</span><span class="s">'name'</span><span class="p">,</span> <span class="n">String</span><span class="p">(</span><span class="mi">50</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span> + <span class="n">Column</span><span class="p">(</span><span class="s">'email'</span><span class="p">,</span> <span class="n">String</span><span class="p">(</span><span class="mi">120</span><span class="p">),</span> <span class="n">unique</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> +<span class="p">)</span> +<span class="n">mapper</span><span class="p">(</span><span class="n">User</span><span class="p">,</span> <span class="n">users</span><span class="p">)</span> +</pre></div> +</div> +<p>Querying and inserting works exactly the same as in the example above.</p> +</div> +<div class="section" id="sql-abstraction-layer"> +<h2>SQL Abstraction Layer<a class="headerlink" href="#sql-abstraction-layer" title="Permalink to this headline">¶</a></h2> +<p>If you just want to use the database system (and SQL) abstraction layer +you basically only need the engine:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">sqlalchemy</span> <span class="kn">import</span> <span class="n">create_engine</span><span class="p">,</span> <span class="n">MetaData</span> + +<span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="s">'sqlite:////tmp/test.db'</span><span class="p">,</span> <span class="n">convert_unicode</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> +<span class="n">metadata</span> <span class="o">=</span> <span class="n">MetaData</span><span class="p">(</span><span class="n">bind</span><span class="o">=</span><span class="n">engine</span><span class="p">)</span> +</pre></div> +</div> +<p>Then you can either declare the tables in your code like in the examples +above, or automatically load them:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="n">users</span> <span class="o">=</span> <span class="n">Table</span><span class="p">(</span><span class="s">'users'</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">autoload</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> +</pre></div> +</div> +<p>To insert data you can use the <cite>insert</cite> method. We have to get a +connection first so that we can use a transaction:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">con</span> <span class="o">=</span> <span class="n">engine</span><span class="o">.</span><span class="n">connect</span><span class="p">()</span> +<span class="gp">>>> </span><span class="n">con</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">users</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="n">name</span><span class="o">=</span><span class="s">'admin'</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="s">'admin@localhost'</span><span class="p">))</span> +</pre></div> +</div> +<p>SQLAlchemy will automatically commit for us.</p> +<p>To query your database, you use the engine directly or use a connection:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">users</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="n">users</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">execute</span><span class="p">()</span><span class="o">.</span><span class="n">first</span><span class="p">()</span> +<span class="go">(1, u'admin', u'admin@localhost')</span> +</pre></div> +</div> +<p>These results are also dict-like tuples:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">r</span> <span class="o">=</span> <span class="n">users</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="n">users</span><span class="o">.</span><span class="n">c</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">execute</span><span class="p">()</span><span class="o">.</span><span class="n">first</span><span class="p">()</span> +<span class="gp">>>> </span><span class="n">r</span><span class="p">[</span><span class="s">'name'</span><span class="p">]</span> +<span class="go">u'admin'</span> +</pre></div> +</div> +<p>You can also pass strings of SQL statements to the +<a class="reference external" href="http://www.sqlalchemy.org/docs/core/connections.html#sqlalchemy.engine.base.Connection.execute" title="(in SQLAlchemy v0.7)"><tt class="xref py py-meth docutils literal"><span class="pre">execute()</span></tt></a> method:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="n">engine</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="s">'select * from users where id = :1'</span><span class="p">,</span> <span class="p">[</span><span class="mi">1</span><span class="p">])</span><span class="o">.</span><span class="n">first</span><span class="p">()</span> +<span class="go">(1, u'admin', u'admin@localhost')</span> +</pre></div> +</div> +<p>For more information about SQLAlchemy, head over to the +<a class="reference external" href="http://sqlalchemy.org/">website</a>.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">SQLAlchemy in Flask</a><ul> +<li><a class="reference internal" href="#flask-sqlalchemy-extension">Flask-SQLAlchemy Extension</a></li> +<li><a class="reference internal" href="#declarative">Declarative</a></li> +<li><a class="reference internal" href="#manual-object-relational-mapping">Manual Object Relational Mapping</a></li> +<li><a class="reference internal" href="#sql-abstraction-layer">SQL Abstraction Layer</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="sqlite3.html" title="previous chapter">Using SQLite 3 with Flask</a></li> + <li>Next: <a href="fileuploads.html" title="next chapter">Uploading Files</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/sqlalchemy.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/sqlite3.html b/app/static/doc/flask-docs/patterns/sqlite3.html new file mode 100644 index 0000000..8e892e3 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/sqlite3.html @@ -0,0 +1,226 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Using SQLite 3 with Flask — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="SQLAlchemy in Flask" href="sqlalchemy.html" /> + <link rel="prev" title="Deploying with Fabric" href="fabric.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="sqlalchemy.html" title="SQLAlchemy in Flask" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="fabric.html" title="Deploying with Fabric" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="using-sqlite-3-with-flask"> +<span id="sqlite3"></span><h1>Using SQLite 3 with Flask<a class="headerlink" href="#using-sqlite-3-with-flask" title="Permalink to this headline">¶</a></h1> +<p>In Flask you can implement the opening of database connections at the +beginning of the request and closing at the end with the +<a class="reference internal" href="../api.html#flask.Flask.before_request" title="flask.Flask.before_request"><tt class="xref py py-meth docutils literal"><span class="pre">before_request()</span></tt></a> and <a class="reference internal" href="../api.html#flask.Flask.teardown_request" title="flask.Flask.teardown_request"><tt class="xref py py-meth docutils literal"><span class="pre">teardown_request()</span></tt></a> +decorators in combination with the special <a class="reference internal" href="../api.html#flask.g" title="flask.g"><tt class="xref py py-class docutils literal"><span class="pre">g</span></tt></a> object.</p> +<p>So here is a simple example of how you can use SQLite 3 with Flask:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">sqlite3</span> +<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">g</span> + +<span class="n">DATABASE</span> <span class="o">=</span> <span class="s">'/path/to/database.db'</span> + +<span class="k">def</span> <span class="nf">connect_db</span><span class="p">():</span> + <span class="k">return</span> <span class="n">sqlite3</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">DATABASE</span><span class="p">)</span> + +<span class="nd">@app.before_request</span> +<span class="k">def</span> <span class="nf">before_request</span><span class="p">():</span> + <span class="n">g</span><span class="o">.</span><span class="n">db</span> <span class="o">=</span> <span class="n">connect_db</span><span class="p">()</span> + +<span class="nd">@app.teardown_request</span> +<span class="k">def</span> <span class="nf">teardown_request</span><span class="p">(</span><span class="n">exception</span><span class="p">):</span> + <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="s">'db'</span><span class="p">):</span> + <span class="n">g</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> +</pre></div> +</div> +<div class="admonition note"> +<p class="first admonition-title">Note</p> +<p class="last">Please keep in mind that the teardown request functions are always +executed, even if a before-request handler failed or was never +executed. Because of this we have to make sure here that the database +is there before we close it.</p> +</div> +<div class="section" id="connect-on-demand"> +<h2>Connect on Demand<a class="headerlink" href="#connect-on-demand" title="Permalink to this headline">¶</a></h2> +<p>The downside of this approach is that this will only work if Flask +executed the before-request handlers for you. If you are attempting to +use the database from a script or the interactive Python shell you would +have to do something like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">test_request_context</span><span class="p">():</span> + <span class="n">app</span><span class="o">.</span><span class="n">preprocess_request</span><span class="p">()</span> + <span class="c"># now you can use the g.db object</span> +</pre></div> +</div> +<p>In order to trigger the execution of the connection code. You won’t be +able to drop the dependency on the request context this way, but you could +make it so that the application connects when necessary:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">get_connection</span><span class="p">():</span> + <span class="n">db</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">g</span><span class="p">,</span> <span class="s">'_db'</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> + <span class="k">if</span> <span class="n">db</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> + <span class="n">db</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">_db</span> <span class="o">=</span> <span class="n">connect_db</span><span class="p">()</span> + <span class="k">return</span> <span class="n">db</span> +</pre></div> +</div> +<p>Downside here is that you have to use <tt class="docutils literal"><span class="pre">db</span> <span class="pre">=</span> <span class="pre">get_connection()</span></tt> instead of +just being able to use <tt class="docutils literal"><span class="pre">g.db</span></tt> directly.</p> +</div> +<div class="section" id="easy-querying"> +<span id="id1"></span><h2>Easy Querying<a class="headerlink" href="#easy-querying" title="Permalink to this headline">¶</a></h2> +<p>Now in each request handling function you can access <cite>g.db</cite> to get the +current open database connection. To simplify working with SQLite, a +helper function can be useful:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">query_db</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">args</span><span class="o">=</span><span class="p">(),</span> <span class="n">one</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span> + <span class="n">cur</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">,</span> <span class="n">args</span><span class="p">)</span> + <span class="n">rv</span> <span class="o">=</span> <span class="p">[</span><span class="nb">dict</span><span class="p">((</span><span class="n">cur</span><span class="o">.</span><span class="n">description</span><span class="p">[</span><span class="n">idx</span><span class="p">][</span><span class="mi">0</span><span class="p">],</span> <span class="n">value</span><span class="p">)</span> + <span class="k">for</span> <span class="n">idx</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">row</span><span class="p">))</span> <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">cur</span><span class="o">.</span><span class="n">fetchall</span><span class="p">()]</span> + <span class="k">return</span> <span class="p">(</span><span class="n">rv</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="k">if</span> <span class="n">rv</span> <span class="k">else</span> <span class="bp">None</span><span class="p">)</span> <span class="k">if</span> <span class="n">one</span> <span class="k">else</span> <span class="n">rv</span> +</pre></div> +</div> +<p>This handy little function makes working with the database much more +pleasant than it is by just using the raw cursor and connection objects.</p> +<p>Here is how you can use it:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">user</span> <span class="ow">in</span> <span class="n">query_db</span><span class="p">(</span><span class="s">'select * from users'</span><span class="p">):</span> + <span class="k">print</span> <span class="n">user</span><span class="p">[</span><span class="s">'username'</span><span class="p">],</span> <span class="s">'has the id'</span><span class="p">,</span> <span class="n">user</span><span class="p">[</span><span class="s">'user_id'</span><span class="p">]</span> +</pre></div> +</div> +<p>Or if you just want a single result:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="n">user</span> <span class="o">=</span> <span class="n">query_db</span><span class="p">(</span><span class="s">'select * from users where username = ?'</span><span class="p">,</span> + <span class="p">[</span><span class="n">the_username</span><span class="p">],</span> <span class="n">one</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> +<span class="k">if</span> <span class="n">user</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> + <span class="k">print</span> <span class="s">'No such user'</span> +<span class="k">else</span><span class="p">:</span> + <span class="k">print</span> <span class="n">the_username</span><span class="p">,</span> <span class="s">'has the id'</span><span class="p">,</span> <span class="n">user</span><span class="p">[</span><span class="s">'user_id'</span><span class="p">]</span> +</pre></div> +</div> +<p>To pass variable parts to the SQL statement, use a question mark in the +statement and pass in the arguments as a list. Never directly add them to +the SQL statement with string formatting because this makes it possible +to attack the application using <a class="reference external" href="http://en.wikipedia.org/wiki/SQL_injection">SQL Injections</a>.</p> +</div> +<div class="section" id="initial-schemas"> +<h2>Initial Schemas<a class="headerlink" href="#initial-schemas" title="Permalink to this headline">¶</a></h2> +<p>Relational databases need schemas, so applications often ship a +<cite>schema.sql</cite> file that creates the database. It’s a good idea to provide +a function that creates the database based on that schema. This function +can do that for you:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">contextlib</span> <span class="kn">import</span> <span class="n">closing</span> + +<span class="k">def</span> <span class="nf">init_db</span><span class="p">():</span> + <span class="k">with</span> <span class="n">closing</span><span class="p">(</span><span class="n">connect_db</span><span class="p">())</span> <span class="k">as</span> <span class="n">db</span><span class="p">:</span> + <span class="k">with</span> <span class="n">app</span><span class="o">.</span><span class="n">open_resource</span><span class="p">(</span><span class="s">'schema.sql'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span> + <span class="n">db</span><span class="o">.</span><span class="n">cursor</span><span class="p">()</span><span class="o">.</span><span class="n">executescript</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">())</span> + <span class="n">db</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span> +</pre></div> +</div> +<p>You can then create such a database from the python shell:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="gp">>>> </span><span class="kn">from</span> <span class="nn">yourapplication</span> <span class="kn">import</span> <span class="n">init_db</span> +<span class="gp">>>> </span><span class="n">init_db</span><span class="p">()</span> +</pre></div> +</div> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Using SQLite 3 with Flask</a><ul> +<li><a class="reference internal" href="#connect-on-demand">Connect on Demand</a></li> +<li><a class="reference internal" href="#easy-querying">Easy Querying</a></li> +<li><a class="reference internal" href="#initial-schemas">Initial Schemas</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="fabric.html" title="previous chapter">Deploying with Fabric</a></li> + <li>Next: <a href="sqlalchemy.html" title="next chapter">SQLAlchemy in Flask</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/sqlite3.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/streaming.html b/app/static/doc/flask-docs/patterns/streaming.html new file mode 100644 index 0000000..9285ec4 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/streaming.html @@ -0,0 +1,172 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Streaming Contents — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Deferred Request Callbacks" href="deferredcallbacks.html" /> + <link rel="prev" title="Adding a favicon" href="favicon.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="deferredcallbacks.html" title="Deferred Request Callbacks" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="favicon.html" title="Adding a favicon" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="streaming-contents"> +<h1>Streaming Contents<a class="headerlink" href="#streaming-contents" title="Permalink to this headline">¶</a></h1> +<p>Sometimes you want to send an enormous amount of data to the client, much +more than you want to keep in memory. When you are generating the data on +the fly though, how do you send that back to the client without the +roundtrip to the filesystem?</p> +<p>The answer is by using generators and direct responses.</p> +<div class="section" id="basic-usage"> +<h2>Basic Usage<a class="headerlink" href="#basic-usage" title="Permalink to this headline">¶</a></h2> +<p>This is a basic view function that generates a lot of CSV data on the fly. +The trick is to have an inner function that uses a generator to generate +data and to then invoke that function and pass it to a response object:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Response</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/large.csv'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">generate_large_csv</span><span class="p">():</span> + <span class="k">def</span> <span class="nf">generate</span><span class="p">():</span> + <span class="k">for</span> <span class="n">row</span> <span class="ow">in</span> <span class="n">iter_all_rows</span><span class="p">():</span> + <span class="k">yield</span> <span class="s">','</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">row</span><span class="p">)</span> <span class="o">+</span> <span class="s">'</span><span class="se">\n</span><span class="s">'</span> + <span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="n">generate</span><span class="p">(),</span> <span class="n">mimetype</span><span class="o">=</span><span class="s">'text/csv'</span><span class="p">)</span> +</pre></div> +</div> +<p>Each <tt class="docutils literal"><span class="pre">yield</span></tt> expression is directly sent to the browser. Now though +that some WSGI middlewares might break streaming, so be careful there in +debug environments with profilers and other things you might have enabled.</p> +</div> +<div class="section" id="streaming-from-templates"> +<h2>Streaming from Templates<a class="headerlink" href="#streaming-from-templates" title="Permalink to this headline">¶</a></h2> +<p>The Jinja2 template engine also supports rendering templates piece by +piece. This functionality is not directly exposed by Flask because it is +quite uncommon, but you can easily do it yourself:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Response</span> + +<span class="k">def</span> <span class="nf">stream_template</span><span class="p">(</span><span class="n">template_name</span><span class="p">,</span> <span class="o">**</span><span class="n">context</span><span class="p">):</span> + <span class="n">app</span><span class="o">.</span><span class="n">update_template_context</span><span class="p">(</span><span class="n">context</span><span class="p">)</span> + <span class="n">t</span> <span class="o">=</span> <span class="n">app</span><span class="o">.</span><span class="n">jinja_env</span><span class="o">.</span><span class="n">get_template</span><span class="p">(</span><span class="n">template_name</span><span class="p">)</span> + <span class="n">rv</span> <span class="o">=</span> <span class="n">t</span><span class="o">.</span><span class="n">stream</span><span class="p">(</span><span class="n">context</span><span class="p">)</span> + <span class="n">rv</span><span class="o">.</span><span class="n">enable_buffering</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> + <span class="k">return</span> <span class="n">rv</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/my-large-page.html'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">render_large_template</span><span class="p">():</span> + <span class="n">rows</span> <span class="o">=</span> <span class="n">iter_all_rows</span><span class="p">()</span> + <span class="k">return</span> <span class="n">Response</span><span class="p">(</span><span class="n">stream_template</span><span class="p">(</span><span class="s">'the_template.html'</span><span class="p">,</span> <span class="n">rows</span><span class="o">=</span><span class="n">rows</span><span class="p">))</span> +</pre></div> +</div> +<p>The trick here is to get the template object from the Jinja2 environment +on the application and to call <tt class="xref py py-meth docutils literal"><span class="pre">stream()</span></tt> instead of +<tt class="xref py py-meth docutils literal"><span class="pre">render()</span></tt> which returns a stream object instead of a +string. Since we’re bypassing the Flask template render functions and +using the template object itself we have to make sure to update the render +context ourselves by calling <a class="reference internal" href="../api.html#flask.Flask.update_template_context" title="flask.Flask.update_template_context"><tt class="xref py py-meth docutils literal"><span class="pre">update_template_context()</span></tt></a>. +The template is then evaluated as the stream is iterated over. Since each +time you do a yield the server will flush the content to the client you +might want to buffer up a few items in the template which you can do with +<tt class="docutils literal"><span class="pre">rv.enable_buffering(size)</span></tt>. <tt class="docutils literal"><span class="pre">5</span></tt> is a sane default.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Streaming Contents</a><ul> +<li><a class="reference internal" href="#basic-usage">Basic Usage</a></li> +<li><a class="reference internal" href="#streaming-from-templates">Streaming from Templates</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="favicon.html" title="previous chapter">Adding a favicon</a></li> + <li>Next: <a href="deferredcallbacks.html" title="next chapter">Deferred Request Callbacks</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/streaming.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/templateinheritance.html b/app/static/doc/flask-docs/patterns/templateinheritance.html new file mode 100644 index 0000000..6075905 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/templateinheritance.html @@ -0,0 +1,173 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Template Inheritance — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Message Flashing" href="flashing.html" /> + <link rel="prev" title="Form Validation with WTForms" href="wtforms.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="flashing.html" title="Message Flashing" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="wtforms.html" title="Form Validation with WTForms" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="template-inheritance"> +<span id="id1"></span><h1>Template Inheritance<a class="headerlink" href="#template-inheritance" title="Permalink to this headline">¶</a></h1> +<p>The most powerful part of Jinja is template inheritance. Template inheritance +allows you to build a base “skeleton” template that contains all the common +elements of your site and defines <strong>blocks</strong> that child templates can override.</p> +<p>Sounds complicated but is very basic. It’s easiest to understand it by starting +with an example.</p> +<div class="section" id="base-template"> +<h2>Base Template<a class="headerlink" href="#base-template" title="Permalink to this headline">¶</a></h2> +<p>This template, which we’ll call <tt class="docutils literal"><span class="pre">layout.html</span></tt>, defines a simple HTML skeleton +document that you might use for a simple two-column page. It’s the job of +“child” templates to fill the empty blocks with content:</p> +<div class="highlight-html+jinja"><div class="highlight"><pre><span class="cp"><!doctype html></span> +<span class="nt"><html></span> + <span class="nt"><head></span> + <span class="cp">{%</span> <span class="k">block</span> <span class="nv">head</span> <span class="cp">%}</span> + <span class="nt"><link</span> <span class="na">rel=</span><span class="s">"stylesheet"</span> <span class="na">href=</span><span class="s">"</span><span class="cp">{{</span> <span class="nv">url_for</span><span class="o">(</span><span class="s1">'static'</span><span class="o">,</span> <span class="nv">filename</span><span class="o">=</span><span class="s1">'style.css'</span><span class="o">)</span> <span class="cp">}}</span><span class="s">"</span><span class="nt">></span> + <span class="nt"><title></span><span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}{%</span> <span class="k">endblock</span> <span class="cp">%}</span> - My Webpage<span class="nt"></title></span> + <span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span> + <span class="nt"></head></span> +<span class="nt"><body></span> + <span class="nt"><div</span> <span class="na">id=</span><span class="s">"content"</span><span class="nt">></span><span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}{%</span> <span class="k">endblock</span> <span class="cp">%}</span><span class="nt"></div></span> + <span class="nt"><div</span> <span class="na">id=</span><span class="s">"footer"</span><span class="nt">></span> + <span class="cp">{%</span> <span class="k">block</span> <span class="nv">footer</span> <span class="cp">%}</span> + <span class="ni">&copy;</span> Copyright 2010 by <span class="nt"><a</span> <span class="na">href=</span><span class="s">"http://domain.invalid/"</span><span class="nt">></span>you<span class="nt"></a></span>. + <span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span> + <span class="nt"></div></span> +<span class="nt"></body></span> +</pre></div> +</div> +<p>In this example, the <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">block</span> <span class="pre">%}</span></tt> tags define four blocks that child templates +can fill in. All the <cite>block</cite> tag does is tell the template engine that a +child template may override those portions of the template.</p> +</div> +<div class="section" id="child-template"> +<h2>Child Template<a class="headerlink" href="#child-template" title="Permalink to this headline">¶</a></h2> +<p>A child template might look like this:</p> +<div class="highlight-html+jinja"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">extends</span> <span class="s2">"layout.html"</span> <span class="cp">%}</span> +<span class="cp">{%</span> <span class="k">block</span> <span class="nv">title</span> <span class="cp">%}</span>Index<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span> +<span class="cp">{%</span> <span class="k">block</span> <span class="nv">head</span> <span class="cp">%}</span> + <span class="cp">{{</span> <span class="nb">super</span><span class="o">()</span> <span class="cp">}}</span> + <span class="nt"><style </span><span class="na">type=</span><span class="s">"text/css"</span><span class="nt">></span> + <span class="nc">.important</span> <span class="p">{</span> <span class="k">color</span><span class="o">:</span> <span class="m">#336699</span><span class="p">;</span> <span class="p">}</span> + <span class="nt"></style></span> +<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span> +<span class="cp">{%</span> <span class="k">block</span> <span class="nv">content</span> <span class="cp">%}</span> + <span class="nt"><h1></span>Index<span class="nt"></h1></span> + <span class="nt"><p</span> <span class="na">class=</span><span class="s">"important"</span><span class="nt">></span> + Welcome on my awesome homepage. +<span class="cp">{%</span> <span class="k">endblock</span> <span class="cp">%}</span> +</pre></div> +</div> +<p>The <tt class="docutils literal"><span class="pre">{%</span> <span class="pre">extends</span> <span class="pre">%}</span></tt> tag is the key here. It tells the template engine that +this template “extends” another template. When the template system evaluates +this template, first it locates the parent. The extends tag must be the +first tag in the template. To render the contents of a block defined in +the parent template, use <tt class="docutils literal"><span class="pre">{{</span> <span class="pre">super()</span> <span class="pre">}}</span></tt>.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Template Inheritance</a><ul> +<li><a class="reference internal" href="#base-template">Base Template</a></li> +<li><a class="reference internal" href="#child-template">Child Template</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="wtforms.html" title="previous chapter">Form Validation with WTForms</a></li> + <li>Next: <a href="flashing.html" title="next chapter">Message Flashing</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/templateinheritance.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/urlprocessors.html b/app/static/doc/flask-docs/patterns/urlprocessors.html new file mode 100644 index 0000000..8e50e36 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/urlprocessors.html @@ -0,0 +1,237 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Using URL Processors — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Deploying with Distribute" href="distribute.html" /> + <link rel="prev" title="Application Dispatching" href="appdispatch.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="distribute.html" title="Deploying with Distribute" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="appdispatch.html" title="Application Dispatching" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="using-url-processors"> +<h1>Using URL Processors<a class="headerlink" href="#using-url-processors" title="Permalink to this headline">¶</a></h1> +<p class="versionadded"> +<span class="versionmodified">New in version 0.7.</span></p> +<p>Flask 0.7 introduces the concept of URL processors. The idea is that you +might have a bunch of resources with common parts in the URL that you +don’t always explicitly want to provide. For instance you might have a +bunch of URLs that have the language code in it but you don’t want to have +to handle it in every single function yourself.</p> +<p>URL processors are especially helpful when combined with blueprints. We +will handle both application specific URL processors here as well as +blueprint specifics.</p> +<div class="section" id="internationalized-application-urls"> +<h2>Internationalized Application URLs<a class="headerlink" href="#internationalized-application-urls" title="Permalink to this headline">¶</a></h2> +<p>Consider an application like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">g</span> + +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/<lang_code>/'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">index</span><span class="p">(</span><span class="n">lang_code</span><span class="p">):</span> + <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">lang_code</span> + <span class="o">...</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/<lang_code>/about'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">about</span><span class="p">(</span><span class="n">lang_code</span><span class="p">):</span> + <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">lang_code</span> + <span class="o">...</span> +</pre></div> +</div> +<p>This is an awful lot of repetition as you have to handle the language code +setting on the <a class="reference internal" href="../api.html#flask.g" title="flask.g"><tt class="xref py py-data docutils literal"><span class="pre">g</span></tt></a> object yourself in every single function. +Sure, a decorator could be used to simplify this, but if you want to +generate URLs from one function to another you would have to still provide +the language code explicitly which can be annoying.</p> +<p>For the latter, this is where <a class="reference internal" href="../api.html#flask.Flask.url_defaults" title="flask.Flask.url_defaults"><tt class="xref py py-func docutils literal"><span class="pre">url_defaults()</span></tt></a> functions +come in. They can automatically inject values into a call for +<a class="reference internal" href="../api.html#flask.url_for" title="flask.url_for"><tt class="xref py py-func docutils literal"><span class="pre">url_for()</span></tt></a> automatically. The code below checks if the +language code is not yet in the dictionary of URL values and if the +endpoint wants a value named <tt class="docutils literal"><span class="pre">'lang_code'</span></tt>:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="nd">@app.url_defaults</span> +<span class="k">def</span> <span class="nf">add_language_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span> + <span class="k">if</span> <span class="s">'lang_code'</span> <span class="ow">in</span> <span class="n">values</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span><span class="p">:</span> + <span class="k">return</span> + <span class="k">if</span> <span class="n">app</span><span class="o">.</span><span class="n">url_map</span><span class="o">.</span><span class="n">is_endpoint_expecting</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="s">'lang_code'</span><span class="p">):</span> + <span class="n">values</span><span class="p">[</span><span class="s">'lang_code'</span><span class="p">]</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> +</pre></div> +</div> +<p>The method <a class="reference external" href="http://werkzeug.pocoo.org/docs/routing/#werkzeug.routing.Map.is_endpoint_expecting" title="(in Werkzeug v0.7)"><tt class="xref py py-meth docutils literal"><span class="pre">is_endpoint_expecting()</span></tt></a> of the URL +map can be used to figure out if it would make sense to provide a language +code for the given endpoint.</p> +<p>The reverse of that function are +<a class="reference internal" href="../api.html#flask.Flask.url_value_preprocessor" title="flask.Flask.url_value_preprocessor"><tt class="xref py py-meth docutils literal"><span class="pre">url_value_preprocessor()</span></tt></a>s. They are executed right +after the request was matched and can execute code based on the URL +values. The idea is that they pull information out of the values +dictionary and put it somewhere else:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="nd">@app.url_value_preprocessor</span> +<span class="k">def</span> <span class="nf">pull_lang_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span> + <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'lang_code'</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> +</pre></div> +</div> +<p>That way you no longer have to do the <cite>lang_code</cite> assigment to +<a class="reference internal" href="../api.html#flask.g" title="flask.g"><tt class="xref py py-data docutils literal"><span class="pre">g</span></tt></a> in every function. You can further improve that by +writing your own decorator that prefixes URLs with the language code, but +the more beautiful solution is using a blueprint. Once the +<tt class="docutils literal"><span class="pre">'lang_code'</span></tt> is popped from the values dictionary and it will no longer +be forwarded to the view function reducing the code to this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span><span class="p">,</span> <span class="n">g</span> + +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> + +<span class="nd">@app.url_defaults</span> +<span class="k">def</span> <span class="nf">add_language_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span> + <span class="k">if</span> <span class="s">'lang_code'</span> <span class="ow">in</span> <span class="n">values</span> <span class="ow">or</span> <span class="ow">not</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span><span class="p">:</span> + <span class="k">return</span> + <span class="k">if</span> <span class="n">app</span><span class="o">.</span><span class="n">url_map</span><span class="o">.</span><span class="n">is_endpoint_expecting</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="s">'lang_code'</span><span class="p">):</span> + <span class="n">values</span><span class="p">[</span><span class="s">'lang_code'</span><span class="p">]</span> <span class="o">=</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> + +<span class="nd">@app.url_value_preprocessor</span> +<span class="k">def</span> <span class="nf">pull_lang_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span> + <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'lang_code'</span><span class="p">,</span> <span class="bp">None</span><span class="p">)</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/<lang_code>/'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">index</span><span class="p">():</span> + <span class="o">...</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/<lang_code>/about'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">about</span><span class="p">():</span> + <span class="o">...</span> +</pre></div> +</div> +</div> +<div class="section" id="internationalized-blueprint-urls"> +<h2>Internationalized Blueprint URLs<a class="headerlink" href="#internationalized-blueprint-urls" title="Permalink to this headline">¶</a></h2> +<p>Because blueprints can automatically prefix all URLs with a common string +it’s easy to automatically do that for every function. Furthermore +blueprints can have per-blueprint URL processors which removes a whole lot +of logic from the <a class="reference internal" href="../api.html#flask.Flask.url_defaults" title="flask.Flask.url_defaults"><tt class="xref py py-meth docutils literal"><span class="pre">url_defaults()</span></tt></a> function because it no +longer has to check if the URL is really interested in a <tt class="docutils literal"><span class="pre">'lang_code'</span></tt> +parameter:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Blueprint</span><span class="p">,</span> <span class="n">g</span> + +<span class="n">bp</span> <span class="o">=</span> <span class="n">Blueprint</span><span class="p">(</span><span class="s">'frontend'</span><span class="p">,</span> <span class="n">__name__</span><span class="p">,</span> <span class="n">url_prefix</span><span class="o">=</span><span class="s">'/<lang_code>'</span><span class="p">)</span> + +<span class="nd">@bp.url_defaults</span> +<span class="k">def</span> <span class="nf">add_language_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span> + <span class="n">values</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s">'lang_code'</span><span class="p">,</span> <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span><span class="p">)</span> + +<span class="nd">@bp.url_value_preprocessor</span> +<span class="k">def</span> <span class="nf">pull_lang_code</span><span class="p">(</span><span class="n">endpoint</span><span class="p">,</span> <span class="n">values</span><span class="p">):</span> + <span class="n">g</span><span class="o">.</span><span class="n">lang_code</span> <span class="o">=</span> <span class="n">values</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s">'lang_code'</span><span class="p">)</span> + +<span class="nd">@bp.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">index</span><span class="p">():</span> + <span class="o">...</span> + +<span class="nd">@bp.route</span><span class="p">(</span><span class="s">'/about'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">about</span><span class="p">():</span> + <span class="o">...</span> +</pre></div> +</div> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Using URL Processors</a><ul> +<li><a class="reference internal" href="#internationalized-application-urls">Internationalized Application URLs</a></li> +<li><a class="reference internal" href="#internationalized-blueprint-urls">Internationalized Blueprint URLs</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="appdispatch.html" title="previous chapter">Application Dispatching</a></li> + <li>Next: <a href="distribute.html" title="next chapter">Deploying with Distribute</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/urlprocessors.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/viewdecorators.html b/app/static/doc/flask-docs/patterns/viewdecorators.html new file mode 100644 index 0000000..9a10276 --- /dev/null +++ b/app/static/doc/flask-docs/patterns/viewdecorators.html @@ -0,0 +1,274 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>View Decorators — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Form Validation with WTForms" href="wtforms.html" /> + <link rel="prev" title="Caching" href="caching.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="wtforms.html" title="Form Validation with WTForms" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="caching.html" title="Caching" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="view-decorators"> +<h1>View Decorators<a class="headerlink" href="#view-decorators" title="Permalink to this headline">¶</a></h1> +<p>Python has a really interesting feature called function decorators. This +allow some really neat things for web applications. Because each view in +Flask is a function decorators can be used to inject additional +functionality to one or more functions. The <a class="reference internal" href="../api.html#flask.Flask.route" title="flask.Flask.route"><tt class="xref py py-meth docutils literal"><span class="pre">route()</span></tt></a> +decorator is the one you probably used already. But there are use cases +for implementing your own decorator. For instance, imagine you have a +view that should only be used by people that are logged in to. If a user +goes to the site and is not logged in, they should be redirected to the +login page. This is a good example of a use case where a decorator is an +excellent solution.</p> +<div class="section" id="login-required-decorator"> +<h2>Login Required Decorator<a class="headerlink" href="#login-required-decorator" title="Permalink to this headline">¶</a></h2> +<p>So let’s implement such a decorator. A decorator is a function that +returns a function. Pretty simple actually. The only thing you have to +keep in mind when implementing something like this is to update the +<cite>__name__</cite>, <cite>__module__</cite> and some other attributes of a function. This is +often forgotten, but you don’t have to do that by hand, there is a +function for that that is used like a decorator (<a class="reference external" href="http://docs.python.org/dev/library/functools.html#functools.wraps" title="(in Python v3.3)"><tt class="xref py py-func docutils literal"><span class="pre">functools.wraps()</span></tt></a>).</p> +<p>This example assumes that the login page is called <tt class="docutils literal"><span class="pre">'login'</span></tt> and that +the current user is stored as <cite>g.user</cite> and <cite>None</cite> if there is no-one +logged in:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">wraps</span> +<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">g</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="n">redirect</span><span class="p">,</span> <span class="n">url_for</span> + +<span class="k">def</span> <span class="nf">login_required</span><span class="p">(</span><span class="n">f</span><span class="p">):</span> + <span class="nd">@wraps</span><span class="p">(</span><span class="n">f</span><span class="p">)</span> + <span class="k">def</span> <span class="nf">decorated_function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> + <span class="k">if</span> <span class="n">g</span><span class="o">.</span><span class="n">user</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> + <span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s">'login'</span><span class="p">,</span> <span class="nb">next</span><span class="o">=</span><span class="n">request</span><span class="o">.</span><span class="n">url</span><span class="p">))</span> + <span class="k">return</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> + <span class="k">return</span> <span class="n">decorated_function</span> +</pre></div> +</div> +<p>So how would you use that decorator now? Apply it as innermost decorator +to a view function. When applying further decorators, always remember +that the <a class="reference internal" href="../api.html#flask.Flask.route" title="flask.Flask.route"><tt class="xref py py-meth docutils literal"><span class="pre">route()</span></tt></a> decorator is the outermost:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="nd">@app.route</span><span class="p">(</span><span class="s">'/secret_page'</span><span class="p">)</span> +<span class="nd">@login_required</span> +<span class="k">def</span> <span class="nf">secret_page</span><span class="p">():</span> + <span class="k">pass</span> +</pre></div> +</div> +</div> +<div class="section" id="caching-decorator"> +<h2>Caching Decorator<a class="headerlink" href="#caching-decorator" title="Permalink to this headline">¶</a></h2> +<p>Imagine you have a view function that does an expensive calculation and +because of that you would like to cache the generated results for a +certain amount of time. A decorator would be nice for that. We’re +assuming you have set up a cache like mentioned in <a class="reference internal" href="caching.html#caching-pattern"><em>Caching</em></a>.</p> +<p>Here an example cache function. It generates the cache key from a +specific prefix (actually a format string) and the current path of the +request. Notice that we are using a function that first creates the +decorator that then decorates the function. Sounds awful? Unfortunately +it is a little bit more complex, but the code should still be +straightforward to read.</p> +<p>The decorated function will then work as follows</p> +<ol class="arabic simple"> +<li>get the unique cache key for the current request base on the current +path.</li> +<li>get the value for that key from the cache. If the cache returned +something we will return that value.</li> +<li>otherwise the original function is called and the return value is +stored in the cache for the timeout provided (by default 5 minutes).</li> +</ol> +<p>Here the code:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">wraps</span> +<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">request</span> + +<span class="k">def</span> <span class="nf">cached</span><span class="p">(</span><span class="n">timeout</span><span class="o">=</span><span class="mi">5</span> <span class="o">*</span> <span class="mi">60</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s">'view/</span><span class="si">%s</span><span class="s">'</span><span class="p">):</span> + <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span> + <span class="nd">@wraps</span><span class="p">(</span><span class="n">f</span><span class="p">)</span> + <span class="k">def</span> <span class="nf">decorated_function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> + <span class="n">cache_key</span> <span class="o">=</span> <span class="n">key</span> <span class="o">%</span> <span class="n">request</span><span class="o">.</span><span class="n">path</span> + <span class="n">rv</span> <span class="o">=</span> <span class="n">cache</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">cache_key</span><span class="p">)</span> + <span class="k">if</span> <span class="n">rv</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> + <span class="k">return</span> <span class="n">rv</span> + <span class="n">rv</span> <span class="o">=</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> + <span class="n">cache</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="n">cache_key</span><span class="p">,</span> <span class="n">rv</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="n">timeout</span><span class="p">)</span> + <span class="k">return</span> <span class="n">rv</span> + <span class="k">return</span> <span class="n">decorated_function</span> + <span class="k">return</span> <span class="n">decorator</span> +</pre></div> +</div> +<p>Notice that this assumes an instantiated <cite>cache</cite> object is available, see +<a class="reference internal" href="caching.html#caching-pattern"><em>Caching</em></a> for more information.</p> +</div> +<div class="section" id="templating-decorator"> +<h2>Templating Decorator<a class="headerlink" href="#templating-decorator" title="Permalink to this headline">¶</a></h2> +<p>A common pattern invented by the TurboGears guys a while back is a +templating decorator. The idea of that decorator is that you return a +dictionary with the values passed to the template from the view function +and the template is automatically rendered. With that, the following +three examples do exactly the same:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="nd">@app.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">index</span><span class="p">():</span> + <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">'index.html'</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span> +<span class="nd">@templated</span><span class="p">(</span><span class="s">'index.html'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">index</span><span class="p">():</span> + <span class="k">return</span> <span class="nb">dict</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span> + +<span class="nd">@app.route</span><span class="p">(</span><span class="s">'/'</span><span class="p">)</span> +<span class="nd">@templated</span><span class="p">()</span> +<span class="k">def</span> <span class="nf">index</span><span class="p">():</span> + <span class="k">return</span> <span class="nb">dict</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span> +</pre></div> +</div> +<p>As you can see, if no template name is provided it will use the endpoint +of the URL map with dots converted to slashes + <tt class="docutils literal"><span class="pre">'.html'</span></tt>. Otherwise +the provided template name is used. When the decorated function returns, +the dictionary returned is passed to the template rendering function. If +<cite>None</cite> is returned, an empty dictionary is assumed, if something else than +a dictionary is returned we return it from the function unchanged. That +way you can still use the redirect function or return simple strings.</p> +<p>Here the code for that decorator:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">wraps</span> +<span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">request</span> + +<span class="k">def</span> <span class="nf">templated</span><span class="p">(</span><span class="n">template</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span> + <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span> + <span class="nd">@wraps</span><span class="p">(</span><span class="n">f</span><span class="p">)</span> + <span class="k">def</span> <span class="nf">decorated_function</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span> + <span class="n">template_name</span> <span class="o">=</span> <span class="n">template</span> + <span class="k">if</span> <span class="n">template_name</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> + <span class="n">template_name</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">endpoint</span> \ + <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'.'</span><span class="p">,</span> <span class="s">'/'</span><span class="p">)</span> <span class="o">+</span> <span class="s">'.html'</span> + <span class="n">ctx</span> <span class="o">=</span> <span class="n">f</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span> + <span class="k">if</span> <span class="n">ctx</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> + <span class="n">ctx</span> <span class="o">=</span> <span class="p">{}</span> + <span class="k">elif</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span> + <span class="k">return</span> <span class="n">ctx</span> + <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="n">template_name</span><span class="p">,</span> <span class="o">**</span><span class="n">ctx</span><span class="p">)</span> + <span class="k">return</span> <span class="n">decorated_function</span> + <span class="k">return</span> <span class="n">decorator</span> +</pre></div> +</div> +</div> +<div class="section" id="endpoint-decorator"> +<h2>Endpoint Decorator<a class="headerlink" href="#endpoint-decorator" title="Permalink to this headline">¶</a></h2> +<p>When you want to use the werkzeug routing system for more flexibility you +need to map the endpoint as defined in the <a class="reference external" href="http://werkzeug.pocoo.org/docs/routing/#werkzeug.routing.Rule" title="(in Werkzeug v0.7)"><tt class="xref py py-class docutils literal"><span class="pre">Rule</span></tt></a> +to a view function. This is possible with this decorator. For example:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">flask</span> <span class="kn">import</span> <span class="n">Flask</span> +<span class="kn">from</span> <span class="nn">werkzeug.routing</span> <span class="kn">import</span> <span class="n">Rule</span> + +<span class="n">app</span> <span class="o">=</span> <span class="n">Flask</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> +<span class="n">app</span><span class="o">.</span><span class="n">url_map</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">Rule</span><span class="p">(</span><span class="s">'/'</span><span class="p">,</span> <span class="n">endpoint</span><span class="o">=</span><span class="s">'index'</span><span class="p">))</span> + +<span class="nd">@app.endpoint</span><span class="p">(</span><span class="s">'index'</span><span class="p">)</span> +<span class="k">def</span> <span class="nf">my_index</span><span class="p">():</span> + <span class="k">return</span> <span class="s">"Hello world"</span> +</pre></div> +</div> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">View Decorators</a><ul> +<li><a class="reference internal" href="#login-required-decorator">Login Required Decorator</a></li> +<li><a class="reference internal" href="#caching-decorator">Caching Decorator</a></li> +<li><a class="reference internal" href="#templating-decorator">Templating Decorator</a></li> +<li><a class="reference internal" href="#endpoint-decorator">Endpoint Decorator</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="caching.html" title="previous chapter">Caching</a></li> + <li>Next: <a href="wtforms.html" title="next chapter">Form Validation with WTForms</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/viewdecorators.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file diff --git a/app/static/doc/flask-docs/patterns/wtforms.html b/app/static/doc/flask-docs/patterns/wtforms.html new file mode 100644 index 0000000..f998f2e --- /dev/null +++ b/app/static/doc/flask-docs/patterns/wtforms.html @@ -0,0 +1,224 @@ + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> + + +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> + + <title>Form Validation with WTForms — Flask 0.8 documentation</title> + + <link rel="stylesheet" href="../_static/flasky.css" type="text/css" /> + <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> + + <script type="text/javascript"> + var DOCUMENTATION_OPTIONS = { + URL_ROOT: '../', + VERSION: '0.8', + COLLAPSE_INDEX: false, + FILE_SUFFIX: '.html', + HAS_SOURCE: true + }; + </script> + <script type="text/javascript" src="../_static/jquery.js"></script> + <script type="text/javascript" src="../_static/underscore.js"></script> + <script type="text/javascript" src="../_static/doctools.js"></script> + <link rel="top" title="Flask 0.8 documentation" href="../index.html" /> + <link rel="up" title="Patterns for Flask" href="index.html" /> + <link rel="next" title="Template Inheritance" href="templateinheritance.html" /> + <link rel="prev" title="View Decorators" href="viewdecorators.html" /> + + + <link rel="apple-touch-icon" href="../_static/touch-icon.png" /> + + <link media="only screen and (max-device-width: 480px)" href="../_static/small_flask.css" type= "text/css" rel="stylesheet" /> + + </head> + <body> + <div class="related"> + <h3>Navigation</h3> + <ul> + <li class="right" style="margin-right: 10px"> + <a href="../genindex.html" title="General Index" + accesskey="I">index</a></li> + <li class="right" > + <a href="templateinheritance.html" title="Template Inheritance" + accesskey="N">next</a> |</li> + <li class="right" > + <a href="viewdecorators.html" title="View Decorators" + accesskey="P">previous</a> |</li> + <li><a href="../index.html">Flask 0.8 documentation</a> »</li> + <li><a href="index.html" accesskey="U">Patterns for Flask</a> »</li> + </ul> + </div> + + <div class="document"> + <div class="documentwrapper"> + <div class="bodywrapper"> + <div class="body"> + + <div class="section" id="form-validation-with-wtforms"> +<h1>Form Validation with WTForms<a class="headerlink" href="#form-validation-with-wtforms" title="Permalink to this headline">¶</a></h1> +<p>When you have to work with form data submitted by a browser view code +quickly becomes very hard to read. There are libraries out there designed +to make this process easier to manage. One of them is <a class="reference external" href="http://wtforms.simplecodes.com/">WTForms</a> which we +will handle here. If you find yourself in the situation of having many +forms, you might want to give it a try.</p> +<p>When you are working with WTForms you have to define your forms as classes +first. I recommend breaking up the application into multiple modules +(<a class="reference internal" href="packages.html#larger-applications"><em>Larger Applications</em></a>) for that and adding a separate module for the +forms.</p> +<div class="admonition-getting-most-of-wtforms-with-an-extension admonition "> +<p class="first admonition-title">Getting most of WTForms with an Extension</p> +<p class="last">The <a class="reference external" href="http://packages.python.org/Flask-WTF/">Flask-WTF</a> extension expands on this pattern and adds a few +handful little helpers that make working with forms and Flask more +fun. You can get it from <a class="reference external" href="http://pypi.python.org/pypi/Flask-WTF">PyPI</a>.</p> +</div> +<div class="section" id="the-forms"> +<h2>The Forms<a class="headerlink" href="#the-forms" title="Permalink to this headline">¶</a></h2> +<p>This is an example form for a typical registration page:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">wtforms</span> <span class="kn">import</span> <span class="n">Form</span><span class="p">,</span> <span class="n">BooleanField</span><span class="p">,</span> <span class="n">TextField</span><span class="p">,</span> <span class="n">validators</span> + +<span class="k">class</span> <span class="nc">RegistrationForm</span><span class="p">(</span><span class="n">Form</span><span class="p">):</span> + <span class="n">username</span> <span class="o">=</span> <span class="n">TextField</span><span class="p">(</span><span class="s">'Username'</span><span class="p">,</span> <span class="p">[</span><span class="n">validators</span><span class="o">.</span><span class="n">Length</span><span class="p">(</span><span class="nb">min</span><span class="o">=</span><span class="mi">4</span><span class="p">,</span> <span class="nb">max</span><span class="o">=</span><span class="mi">25</span><span class="p">)])</span> + <span class="n">email</span> <span class="o">=</span> <span class="n">TextField</span><span class="p">(</span><span class="s">'Email Address'</span><span class="p">,</span> <span class="p">[</span><span class="n">validators</span><span class="o">.</span><span class="n">Length</span><span class="p">(</span><span class="nb">min</span><span class="o">=</span><span class="mi">6</span><span class="p">,</span> <span class="nb">max</span><span class="o">=</span><span class="mi">35</span><span class="p">)])</span> + <span class="n">password</span> <span class="o">=</span> <span class="n">PasswordField</span><span class="p">(</span><span class="s">'New Password'</span><span class="p">,</span> <span class="p">[</span> + <span class="n">validators</span><span class="o">.</span><span class="n">Required</span><span class="p">(),</span> + <span class="n">validators</span><span class="o">.</span><span class="n">EqualTo</span><span class="p">(</span><span class="s">'confirm'</span><span class="p">,</span> <span class="n">message</span><span class="o">=</span><span class="s">'Passwords must match'</span><span class="p">)</span> + <span class="p">])</span> + <span class="n">confirm</span> <span class="o">=</span> <span class="n">PasswordField</span><span class="p">(</span><span class="s">'Repeat Password'</span><span class="p">)</span> + <span class="n">accept_tos</span> <span class="o">=</span> <span class="n">BooleanField</span><span class="p">(</span><span class="s">'I accept the TOS'</span><span class="p">,</span> <span class="p">[</span><span class="n">validators</span><span class="o">.</span><span class="n">Required</span><span class="p">()])</span> +</pre></div> +</div> +</div> +<div class="section" id="in-the-view"> +<h2>In the View<a class="headerlink" href="#in-the-view" title="Permalink to this headline">¶</a></h2> +<p>In the view function, the usage of this form looks like this:</p> +<div class="highlight-python"><div class="highlight"><pre><span class="nd">@app.route</span><span class="p">(</span><span class="s">'/register'</span><span class="p">,</span> <span class="n">methods</span><span class="o">=</span><span class="p">[</span><span class="s">'GET'</span><span class="p">,</span> <span class="s">'POST'</span><span class="p">])</span> +<span class="k">def</span> <span class="nf">register</span><span class="p">():</span> + <span class="n">form</span> <span class="o">=</span> <span class="n">RegistrationForm</span><span class="p">(</span><span class="n">request</span><span class="o">.</span><span class="n">form</span><span class="p">)</span> + <span class="k">if</span> <span class="n">request</span><span class="o">.</span><span class="n">method</span> <span class="o">==</span> <span class="s">'POST'</span> <span class="ow">and</span> <span class="n">form</span><span class="o">.</span><span class="n">validate</span><span class="p">():</span> + <span class="n">user</span> <span class="o">=</span> <span class="n">User</span><span class="p">(</span><span class="n">form</span><span class="o">.</span><span class="n">username</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="n">form</span><span class="o">.</span><span class="n">email</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> + <span class="n">form</span><span class="o">.</span><span class="n">password</span><span class="o">.</span><span class="n">data</span><span class="p">)</span> + <span class="n">db_session</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">user</span><span class="p">)</span> + <span class="n">flash</span><span class="p">(</span><span class="s">'Thanks for registering'</span><span class="p">)</span> + <span class="k">return</span> <span class="n">redirect</span><span class="p">(</span><span class="n">url_for</span><span class="p">(</span><span class="s">'login'</span><span class="p">))</span> + <span class="k">return</span> <span class="n">render_template</span><span class="p">(</span><span class="s">'register.html'</span><span class="p">,</span> <span class="n">form</span><span class="o">=</span><span class="n">form</span><span class="p">)</span> +</pre></div> +</div> +<p>Notice that we are implying that the view is using SQLAlchemy here +(<a class="reference internal" href="sqlalchemy.html#sqlalchemy-pattern"><em>SQLAlchemy in Flask</em></a>) but this is no requirement of course. Adapt +the code as necessary.</p> +<p>Things to remember:</p> +<ol class="arabic simple"> +<li>create the form from the request <tt class="xref py py-attr docutils literal"><span class="pre">form</span></tt> value if +the data is submitted via the HTTP <cite>POST</cite> method and +<tt class="xref py py-attr docutils literal"><span class="pre">args</span></tt> if the data is submitted as <cite>GET</cite>.</li> +<li>to validate the data, call the <tt class="xref py py-func docutils literal"><span class="pre">validate()</span></tt> +method which will return <cite>True</cite> if the data validates, <cite>False</cite> +otherwise.</li> +<li>to access individual values from the form, access <cite>form.<NAME>.data</cite>.</li> +</ol> +</div> +<div class="section" id="forms-in-templates"> +<h2>Forms in Templates<a class="headerlink" href="#forms-in-templates" title="Permalink to this headline">¶</a></h2> +<p>Now to the template side. When you pass the form to the templates you can +easily render them there. Look at the following example template to see +how easy this is. WTForms does half the form generation for us already. +To make it even nicer, we can write a macro that renders a field with +label and a list of errors if there are any.</p> +<p>Here’s an example <cite>_formhelpers.html</cite> template with such a macro:</p> +<div class="highlight-html+jinja"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">macro</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">field</span><span class="o">)</span> <span class="cp">%}</span> + <span class="nt"><dt></span><span class="cp">{{</span> <span class="nv">field.label</span> <span class="cp">}}</span> + <span class="nt"><dd></span><span class="cp">{{</span> <span class="nv">field</span><span class="o">(**</span><span class="nv">kwargs</span><span class="o">)|</span><span class="nf">safe</span> <span class="cp">}}</span> + <span class="cp">{%</span> <span class="k">if</span> <span class="nv">field.errors</span> <span class="cp">%}</span> + <span class="nt"><ul</span> <span class="na">class=</span><span class="s">"errors"</span><span class="nt">></span> + <span class="cp">{%</span> <span class="k">for</span> <span class="nv">error</span> <span class="k">in</span> <span class="nv">field.errors</span> <span class="cp">%}</span><span class="nt"><li></span><span class="cp">{{</span> <span class="nv">error</span> <span class="cp">}}{%</span> <span class="k">endfor</span> <span class="cp">%}</span> + <span class="nt"></ul></span> + <span class="cp">{%</span> <span class="k">endif</span> <span class="cp">%}</span> + <span class="nt"></dd></span> +<span class="cp">{%</span> <span class="k">endmacro</span> <span class="cp">%}</span> +</pre></div> +</div> +<p>This macro accepts a couple of keyword arguments that are forwarded to +WTForm’s field function that renders the field for us. The keyword +arguments will be inserted as HTML attributes. So for example you can +call <tt class="docutils literal"><span class="pre">render_field(form.username,</span> <span class="pre">class='username')</span></tt> to add a class to +the input element. Note that WTForms returns standard Python unicode +strings, so we have to tell Jinja2 that this data is already HTML escaped +with the <cite>|safe</cite> filter.</p> +<p>Here the <cite>register.html</cite> template for the function we used above which +takes advantage of the <cite>_formhelpers.html</cite> template:</p> +<div class="highlight-html+jinja"><div class="highlight"><pre><span class="cp">{%</span> <span class="k">from</span> <span class="s2">"_formhelpers.html"</span> <span class="k">import</span> <span class="nv">render_field</span> <span class="cp">%}</span> +<span class="nt"><form</span> <span class="na">method=</span><span class="s">"post"</span> <span class="na">action=</span><span class="s">"/register"</span><span class="nt">></span> + <span class="nt"><dl></span> + <span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.username</span><span class="o">)</span> <span class="cp">}}</span> + <span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.email</span><span class="o">)</span> <span class="cp">}}</span> + <span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.password</span><span class="o">)</span> <span class="cp">}}</span> + <span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.confirm</span><span class="o">)</span> <span class="cp">}}</span> + <span class="cp">{{</span> <span class="nv">render_field</span><span class="o">(</span><span class="nv">form.accept_tos</span><span class="o">)</span> <span class="cp">}}</span> + <span class="nt"></dl></span> + <span class="nt"><p><input</span> <span class="na">type=</span><span class="s">submit</span> <span class="na">value=</span><span class="s">Register</span><span class="nt">></span> +<span class="nt"></form></span> +</pre></div> +</div> +<p>For more information about WTForms, head over to the <a class="reference external" href="http://wtforms.simplecodes.com/">WTForms +website</a>.</p> +</div> +</div> + + + </div> + </div> + </div> + <div class="sphinxsidebar"> + <div class="sphinxsidebarwrapper"><p class="logo"><a href="../index.html"> + <img class="logo" src="../_static/flask.png" alt="Logo"/> +</a></p> + <h3><a href="../index.html">Table Of Contents</a></h3> + <ul> +<li><a class="reference internal" href="#">Form Validation with WTForms</a><ul> +<li><a class="reference internal" href="#the-forms">The Forms</a></li> +<li><a class="reference internal" href="#in-the-view">In the View</a></li> +<li><a class="reference internal" href="#forms-in-templates">Forms in Templates</a></li> +</ul> +</li> +</ul> +<h3>Related Topics</h3> +<ul> + <li><a href="../index.html">Documentation overview</a><ul> + <li><a href="index.html">Patterns for Flask</a><ul> + <li>Previous: <a href="viewdecorators.html" title="previous chapter">View Decorators</a></li> + <li>Next: <a href="templateinheritance.html" title="next chapter">Template Inheritance</a></li> + </ul></li> + </ul></li> +</ul> + <h3>This Page</h3> + <ul class="this-page-menu"> + <li><a href="../_sources/patterns/wtforms.txt" + rel="nofollow">Show Source</a></li> + </ul> +<div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="../search.html" method="get"> + <input type="text" name="q" /> + <input type="submit" value="Go" /> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> +</div> +<script type="text/javascript">$('#searchbox').show(0);</script> + </div> + </div> + <div class="clearer"></div> + </div> + <div class="footer"> + © Copyright 2010, Armin Ronacher. + Created using <a href="http://sphinx.pocoo.org/">Sphinx</a>. + </div> + </body> +</html>
\ No newline at end of file |