diff options
Diffstat (limited to 'studio/static/doc/flask-docs/_sources/quickstart.txt')
-rw-r--r-- | studio/static/doc/flask-docs/_sources/quickstart.txt | 824 |
1 files changed, 824 insertions, 0 deletions
diff --git a/studio/static/doc/flask-docs/_sources/quickstart.txt b/studio/static/doc/flask-docs/_sources/quickstart.txt new file mode 100644 index 0000000..34aa3be --- /dev/null +++ b/studio/static/doc/flask-docs/_sources/quickstart.txt @@ -0,0 +1,824 @@ +.. _quickstart: + +Quickstart +========== + +Eager to get started? This page gives a good introduction in how to get +started with Flask. This assumes you already have Flask installed. If +you do not, head over to the :ref:`installation` section. + + +A Minimal Application +--------------------- + +A minimal Flask application looks something like this:: + + from flask import Flask + app = Flask(__name__) + + @app.route('/') + def hello_world(): + return 'Hello World!' + + if __name__ == '__main__': + app.run() + +Just save it as `hello.py` or something similar and run it with your +Python interpreter. Make sure to not call your application `flask.py` +because this would conflict with Flask itself. + +:: + + $ python hello.py + * Running on http://127.0.0.1:5000/ + +Head over to `http://127.0.0.1:5000/ <http://127.0.0.1:5000/>`_, you should +see your hello world greeting. + +So what did that code do? + +1. First we imported the :class:`~flask.Flask` class. An instance of this + class will be our WSGI application. The first argument is the name of + the application's module. If you are using a single module (like here) + you should use `__name__` because depending on if it's started as + application or imported as module the name will be different + (``'__main__'`` versus the actual import name). For more information + on that, have a look at the :class:`~flask.Flask` documentation. +2. Next we create an instance of it. We pass it the name of the module / + package. This is needed so that Flask knows where it should look for + templates, static files and so on. +3. Then we use the :meth:`~flask.Flask.route` decorator to tell Flask + what URL should trigger our function. +4. The function then has a name which is also used to generate URLs to + that particular function, and returns the message we want to display in + the user's browser. +5. Finally we use the :meth:`~flask.Flask.run` function to run the + local server with our application. The ``if __name__ == '__main__':`` + makes sure the server only runs if the script is executed directly from + the Python interpreter and not used as imported module. + +To stop the server, hit control-C. + +.. _public-server: + +.. admonition:: Externally Visible Server + + If you run the server you will notice that the server is only available + from your own computer, not from any other in the network. This is the + default because in debugging mode a user of the application can execute + arbitrary Python code on your computer. If you have `debug` disabled + or trust the users on your network, you can make the server publicly + available. + + Just change the call of the :meth:`~flask.Flask.run` method to look + like this:: + + app.run(host='0.0.0.0') + + This tells your operating system to listen on a public IP. + + +Debug Mode +---------- + +The :meth:`~flask.Flask.run` method is nice to start a local +development server, but you would have to restart it manually after each +change you do to code. That is not very nice and Flask can do better. If +you enable the debug support the server will reload itself on code changes +and also provide you with a helpful debugger if things go wrong. + +There are two ways to enable debugging. Either set that flag on the +application object:: + + app.debug = True + app.run() + +Or pass it to run:: + + app.run(debug=True) + +Both will have exactly the same effect. + +.. admonition:: Attention + + Even though the interactive debugger does not work in forking environments + (which makes it nearly impossible to use on production servers), it still + allows the execution of arbitrary code. That makes it a major security + risk and therefore it **must never be used on production machines**. + +Screenshot of the debugger in action: + +.. image:: _static/debugger.png + :align: center + :class: screenshot + :alt: screenshot of debugger in action + +.. admonition:: Working With Other Debuggers + + Debuggers interfere with each other. If you are using another debugger + (e.g. PyDev or IntelliJ), you may need to set ``app.debug = False``. + + +Routing +------- + +Modern web applications have beautiful URLs. This helps people remember +the URLs which is especially handy for applications that are used from +mobile devices with slower network connections. If the user can directly +go to the desired page without having to hit the index page it is more +likely they will like the page and come back next time. + +As you have seen above, the :meth:`~flask.Flask.route` decorator is used +to bind a function to a URL. Here are some basic examples:: + + @app.route('/') + def index(): + return 'Index Page' + + @app.route('/hello') + def hello(): + return 'Hello World' + +But there is more to it! You can make certain parts of the URL dynamic +and attach multiple rules to a function. + +Variable Rules +`````````````` + +To add variable parts to a URL you can mark these special sections as +``<variable_name>``. Such a part is then passed as keyword argument to +your function. Optionally a converter can be specified by specifying a +rule with ``<converter:variable_name>``. Here are some nice examples:: + + @app.route('/user/<username>') + def show_user_profile(username): + # show the user profile for that user + pass + + @app.route('/post/<int:post_id>') + def show_post(post_id): + # show the post with the given id, the id is an integer + pass + +The following converters exist: + +=========== =========================================== +`int` accepts integers +`float` like `int` but for floating point values +`path` like the default but also accepts slashes +=========== =========================================== + +.. admonition:: Unique URLs / Redirection Behaviour + + Flask's URL rules are based on Werkzeug's routing module. The idea + behind that module is to ensure nice looking and also unique URLs based + on behaviour Apache and earlier servers coined. + + Take these two rules:: + + @app.route('/projects/') + def projects(): + pass + + @app.route('/about') + def about(): + pass + + They look rather similar, the difference is the trailing slash in the + URL *definition*. In the first case, the canonical URL for the + `projects` endpoint has a trailing slash. It's similar to a folder in + that sense. Accessing it without a trailing slash will cause Flask to + redirect to the canonical URL with the trailing slash. + + However in the second case the URL is defined without a slash so it + behaves similar to a file and accessing the URL with a trailing slash + will be a 404 error. + + Why is this? This allows relative URLs to continue working if users + access the page when they forget a trailing slash. This behaviour is + also consistent with how Apache and other servers work. Also, the URLs + will stay unique which helps search engines not indexing the same page + twice. + + +.. _url-building: + +URL Building +```````````` + +If it can match URLs, can it also generate them? Of course it can. To +build a URL to a specific function you can use the :func:`~flask.url_for` +function. It accepts the name of the function as first argument and a +number of keyword arguments, each corresponding to the variable part of +the URL rule. Unknown variable parts are appended to the URL as query +parameter. Here are some examples: + +>>> from flask import Flask, url_for +>>> app = Flask(__name__) +>>> @app.route('/') +... def index(): pass +... +>>> @app.route('/login') +... def login(): pass +... +>>> @app.route('/user/<username>') +... def profile(username): pass +... +>>> with app.test_request_context(): +... print url_for('index') +... print url_for('login') +... print url_for('login', next='/') +... print url_for('profile', username='John Doe') +... +/ +/login +/login?next=/ +/user/John%20Doe + +(This also uses the :meth:`~flask.Flask.test_request_context` method +explained below. It basically tells Flask to think we are handling a +request even though we are not, we are in an interactive Python shell. +Have a look at the explanation below. :ref:`context-locals`). + +Why would you want to build URLs instead of hardcoding them in your +templates? There are three good reasons for this: + +1. reversing is often more descriptive than hardcoding the URLs. Also and + more importantly you can change URLs in one go without having to change + the URLs all over the place. +2. URL building will handle escaping of special characters and Unicode + data transparently for you, you don't have to deal with that. +3. If your application is placed outside the URL root (so say in + ``/myapplication`` instead of ``/``), :func:`~flask.url_for` will + handle that properly for you. + + +HTTP Methods +```````````` + +HTTP (the protocol web applications are speaking) knows different methods +to access URLs. By default a route only answers to `GET` requests, but +that can be changed by providing the `methods` argument to the +:meth:`~flask.Flask.route` decorator. Here are some examples:: + + @app.route('/login', methods=['GET', 'POST']) + def login(): + if request.method == 'POST': + do_the_login() + else: + show_the_login_form() + +If `GET` is present, `HEAD` will be added automatically for you. You +don't have to deal with that. It will also make sure that `HEAD` requests +are handled like the `HTTP RFC`_ (the document describing the HTTP +protocol) demands, so you can completely ignore that part of the HTTP +specification. Likewise as of Flask 0.6, `OPTIONS` is implemented for you +as well automatically. + +You have no idea what an HTTP method is? Worry not, here is a quick +introduction to HTTP methods and why they matter: + +The HTTP method (also often called "the verb") tells the server what the +clients wants to *do* with the requested page. The following methods are +very common: + +`GET` + The browser tells the server to just *get* the information stored on + that page and send it. This is probably the most common method. + +`HEAD` + The browser tells the server to get the information, but it is only + interested in the *headers*, not the content of the page. An + application is supposed to handle that as if a `GET` request was + received but to not deliver the actual content. In Flask you don't + have to deal with that at all, the underlying Werkzeug library handles + that for you. + +`POST` + The browser tells the server that it wants to *post* some new + information to that URL and that the server must ensure the data is + stored and only stored once. This is how HTML forms are usually + transmitting data to the server. + +`PUT` + Similar to `POST` but the server might trigger the store procedure + multiple times by overwriting the old values more than once. Now you + might be asking why is this useful, but there are some good reasons + to do it this way. Consider that the connection gets lost during + transmission: in this situation a system between the browser and the + server might receive the request safely a second time without breaking + things. With `POST` that would not be possible because it must only + be triggered once. + +`DELETE` + Remove the information at the given location. + +`OPTIONS` + Provides a quick way for a client to figure out which methods are + supported by this URL. Starting with Flask 0.6, this is implemented + for you automatically. + +Now the interesting part is that in HTML4 and XHTML1, the only methods a +form can submit to the server are `GET` and `POST`. But with JavaScript +and future HTML standards you can use the other methods as well. Furthermore +HTTP has become quite popular lately and browsers are no longer the only +clients that are using HTTP. For instance, many revision control system +use it. + +.. _HTTP RFC: http://www.ietf.org/rfc/rfc2068.txt + +Static Files +------------ + +Dynamic web applications need static files as well. That's usually where +the CSS and JavaScript files are coming from. Ideally your web server is +configured to serve them for you, but during development Flask can do that +as well. Just create a folder called `static` in your package or next to +your module and it will be available at `/static` on the application. + +To generate URLs to that part of the URL, use the special ``'static'`` URL +name:: + + url_for('static', filename='style.css') + +The file has to be stored on the filesystem as ``static/style.css``. + +Rendering Templates +------------------- + +Generating HTML from within Python is not fun, and actually pretty +cumbersome because you have to do the HTML escaping on your own to keep +the application secure. Because of that Flask configures the `Jinja2 +<http://jinja.pocoo.org/2/>`_ template engine for you automatically. + +To render a template you can use the :func:`~flask.render_template` +method. All you have to do is to provide the name of the template and the +variables you want to pass to the template engine as keyword arguments. +Here's a simple example of how to render a template:: + + from flask import render_template + + @app.route('/hello/') + @app.route('/hello/<name>') + def hello(name=None): + return render_template('hello.html', name=name) + +Flask will look for templates in the `templates` folder. So if your +application is a module, that folder is next to that module, if it's a +package it's actually inside your package: + +**Case 1**: a module:: + + /application.py + /templates + /hello.html + +**Case 2**: a package:: + + /application + /__init__.py + /templates + /hello.html + +For templates you can use the full power of Jinja2 templates. Head over +to the the official `Jinja2 Template Documentation +<http://jinja.pocoo.org/2/documentation/templates>`_ for more information. + +Here is an example template: + +.. sourcecode:: html+jinja + + <!doctype html> + <title>Hello from Flask</title> + {% if name %} + <h1>Hello {{ name }}!</h1> + {% else %} + <h1>Hello World!</h1> + {% endif %} + +Inside templates you also have access to the :class:`~flask.request`, +:class:`~flask.session` and :class:`~flask.g` [#]_ objects +as well as the :func:`~flask.get_flashed_messages` function. + +Templates are especially useful if inheritance is used. If you want to +know how that works, head over to the :ref:`template-inheritance` pattern +documentation. Basically template inheritance makes it possible to keep +certain elements on each page (like header, navigation and footer). + +Automatic escaping is enabled, so if name contains HTML it will be escaped +automatically. If you can trust a variable and you know that it will be +safe HTML (because for example it came from a module that converts wiki +markup to HTML) you can mark it as safe by using the +:class:`~jinja2.Markup` class or by using the ``|safe`` filter in the +template. Head over to the Jinja 2 documentation for more examples. + +Here is a basic introduction to how the :class:`~jinja2.Markup` class works: + +>>> from flask import Markup +>>> Markup('<strong>Hello %s!</strong>') % '<blink>hacker</blink>' +Markup(u'<strong>Hello <blink>hacker</blink>!</strong>') +>>> Markup.escape('<blink>hacker</blink>') +Markup(u'<blink>hacker</blink>') +>>> Markup('<em>Marked up</em> » HTML').striptags() +u'Marked up \xbb HTML' + +.. versionchanged:: 0.5 + + Autoescaping is no longer enabled for all templates. The following + extensions for templates trigger autoescaping: ``.html``, ``.htm``, + ``.xml``, ``.xhtml``. Templates loaded from a string will have + autoescaping disabled. + +.. [#] Unsure what that :class:`~flask.g` object is? It's something in which + you can store information for your own needs, check the documentation of + that object (:class:`~flask.g`) and the :ref:`sqlite3` for more + information. + + +Accessing Request Data +---------------------- + +For web applications it's crucial to react to the data a client sent to +the server. In Flask this information is provided by the global +:class:`~flask.request` object. If you have some experience with Python +you might be wondering how that object can be global and how Flask +manages to still be threadsafe. The answer are context locals: + + +.. _context-locals: + +Context Locals +`````````````` + +.. admonition:: Insider Information + + If you want to understand how that works and how you can implement + tests with context locals, read this section, otherwise just skip it. + +Certain objects in Flask are global objects, but not of the usual kind. +These objects are actually proxies to objects that are local to a specific +context. What a mouthful. But that is actually quite easy to understand. + +Imagine the context being the handling thread. A request comes in and the +webserver decides to spawn a new thread (or something else, the +underlying object is capable of dealing with other concurrency systems +than threads as well). When Flask starts its internal request handling it +figures out that the current thread is the active context and binds the +current application and the WSGI environments to that context (thread). +It does that in an intelligent way that one application can invoke another +application without breaking. + +So what does this mean to you? Basically you can completely ignore that +this is the case unless you are doing something like unittesting. You +will notice that code that depends on a request object will suddenly break +because there is no request object. The solution is creating a request +object yourself and binding it to the context. The easiest solution for +unittesting is by using the :meth:`~flask.Flask.test_request_context` +context manager. In combination with the `with` statement it will bind a +test request so that you can interact with it. Here is an example:: + + from flask import request + + with app.test_request_context('/hello', method='POST'): + # now you can do something with the request until the + # end of the with block, such as basic assertions: + assert request.path == '/hello' + assert request.method == 'POST' + +The other possibility is passing a whole WSGI environment to the +:meth:`~flask.Flask.request_context` method:: + + from flask import request + + with app.request_context(environ): + assert request.method == 'POST' + +The Request Object +`````````````````` + +The request object is documented in the API section and we will not cover +it here in detail (see :class:`~flask.request`). Here is a broad overview of +some of the most common operations. First of all you have to import it from +the `flask` module:: + + from flask import request + +The current request method is available by using the +:attr:`~flask.request.method` attribute. To access form data (data +transmitted in a `POST` or `PUT` request) you can use the +:attr:`~flask.request.form` attribute. Here is a full example of the two +attributes mentioned above:: + + @app.route('/login', methods=['POST', 'GET']) + def login(): + error = None + if request.method == 'POST': + if valid_login(request.form['username'], + request.form['password']): + return log_the_user_in(request.form['username']) + else: + error = 'Invalid username/password' + # this is executed if the request method was GET or the + # credentials were invalid + +What happens if the key does not exist in the `form` attribute? In that +case a special :exc:`KeyError` is raised. You can catch it like a +standard :exc:`KeyError` but if you don't do that, a HTTP 400 Bad Request +error page is shown instead. So for many situations you don't have to +deal with that problem. + +To access parameters submitted in the URL (``?key=value``) you can use the +:attr:`~flask.request.args` attribute:: + + searchword = request.args.get('q', '') + +We recommend accessing URL parameters with `get` or by catching the +`KeyError` because users might change the URL and presenting them a 400 +bad request page in that case is not user friendly. + +For a full list of methods and attributes of the request object, head over +to the :class:`~flask.request` documentation. + + +File Uploads +```````````` + +You can handle uploaded files with Flask easily. Just make sure not to +forget to set the ``enctype="multipart/form-data"`` attribute on your HTML +form, otherwise the browser will not transmit your files at all. + +Uploaded files are stored in memory or at a temporary location on the +filesystem. You can access those files by looking at the +:attr:`~flask.request.files` attribute on the request object. Each +uploaded file is stored in that dictionary. It behaves just like a +standard Python :class:`file` object, but it also has a +:meth:`~werkzeug.datastructures.FileStorage.save` method that allows you to store that +file on the filesystem of the server. Here is a simple example showing how +that works:: + + from flask import request + + @app.route('/upload', methods=['GET', 'POST']) + def upload_file(): + if request.method == 'POST': + f = request.files['the_file'] + f.save('/var/www/uploads/uploaded_file.txt') + ... + +If you want to know how the file was named on the client before it was +uploaded to your application, you can access the +:attr:`~werkzeug.datastructures.FileStorage.filename` attribute. However please keep in +mind that this value can be forged so never ever trust that value. If you +want to use the filename of the client to store the file on the server, +pass it through the :func:`~werkzeug.utils.secure_filename` function that +Werkzeug provides for you:: + + from flask import request + from werkzeug import secure_filename + + @app.route('/upload', methods=['GET', 'POST']) + def upload_file(): + if request.method == 'POST': + f = request.files['the_file'] + f.save('/var/www/uploads/' + secure_filename(f.filename)) + ... + +For some better examples, checkout the :ref:`uploading-files` pattern. + +Cookies +``````` + +To access cookies you can use the :attr:`~flask.Request.cookies` +attribute. To set cookies you can use the +:attr:`~flask.Response.set_cookie` method of response objects. The +:attr:`~flask.Request.cookies` attribute of request objects is a +dictionary with all the cookies the client transmits. If you want to use +sessions, do not use the cookies directly but instead use the +:ref:`sessions` in Flask that add some security on top of cookies for you. + +Reading cookies:: + + from flask import request + + @app.route('/') + def index(): + username = request.cookies.get('username') + # use cookies.get(key) instead of cookies[key] to not get a + # KeyError if the cookie is missing. + +Storing cookies:: + + from flask import make_response + + @app.route('/') + def index(): + resp = make_response(render_template(...)) + resp.set_cookie('username', 'the username') + return resp + +Note that cookies are set on response objects. Since you normally you +just return strings from the view functions Flask will convert them into +response objects for you. If you explicitly want to do that you can use +the :meth:`~flask.make_response` function and then modify it. + +Sometimes you might want to set a cookie at a point where the response +object does not exist yet. This is possible by utilizing the +:ref:`deferred-callbacks` pattern. + +For this also see :ref:`about-responses`. + +Redirects and Errors +-------------------- + +To redirect a user to somewhere else you can use the +:func:`~flask.redirect` function. To abort a request early with an error +code use the :func:`~flask.abort` function. Here an example how this works:: + + from flask import abort, redirect, url_for + + @app.route('/') + def index(): + return redirect(url_for('login')) + + @app.route('/login') + def login(): + abort(401) + this_is_never_executed() + +This is a rather pointless example because a user will be redirected from +the index to a page they cannot access (401 means access denied) but it +shows how that works. + +By default a black and white error page is shown for each error code. If +you want to customize the error page, you can use the +:meth:`~flask.Flask.errorhandler` decorator:: + + from flask import render_template + + @app.errorhandler(404) + def page_not_found(error): + return render_template('page_not_found.html'), 404 + +Note the ``404`` after the :func:`~flask.render_template` call. This +tells Flask that the status code of that page should be 404 which means +not found. By default 200 is assumed which translates to: all went well. + +.. _about-responses: + +About Responses +--------------- + +The return value from a view function is automatically converted into a +response object for you. If the return value is a string it's converted +into a response object with the string as response body, an ``200 OK`` +error code and a ``text/html`` mimetype. The logic that Flask applies to +converting return values into response objects is as follows: + +1. If a response object of the correct type is returned it's directly + returned from the view. +2. If it's a string, a response object is created with that data and the + default parameters. +3. If a tuple is returned the response object is created by passing the + tuple as arguments to the response object's constructor. +4. If neither of that works, Flask will assume the return value is a + valid WSGI application and converts that into a response object. + +If you want to get hold of the resulting response object inside the view +you can use the :func:`~flask.make_response` function. + +Imagine you have a view like this: + +.. sourcecode:: python + + @app.errorhandler(404) + def not_found(error): + return render_template('error.html'), 404 + +You just need to wrap the return expression with +:func:`~flask.make_response` and get the result object to modify it, then +return it: + +.. sourcecode:: python + + @app.errorhandler(404) + def not_found(error): + resp = make_response(render_template('error.html'), 404) + resp.headers['X-Something'] = 'A value' + return resp + +.. _sessions: + +Sessions +-------- + +Besides the request object there is also a second object called +:class:`~flask.session` that allows you to store information specific to a +user from one request to the next. This is implemented on top of cookies +for you and signs the cookies cryptographically. What this means is that +the user could look at the contents of your cookie but not modify it, +unless they know the secret key used for signing. + +In order to use sessions you have to set a secret key. Here is how +sessions work:: + + from flask import Flask, session, redirect, url_for, escape, request + + app = Flask(__name__) + + @app.route('/') + def index(): + if 'username' in session: + return 'Logged in as %s' % escape(session['username']) + return 'You are not logged in' + + @app.route('/login', methods=['GET', 'POST']) + def login(): + if request.method == 'POST': + session['username'] = request.form['username'] + return redirect(url_for('index')) + return ''' + <form action="" method="post"> + <p><input type=text name=username> + <p><input type=submit value=Login> + </form> + ''' + + @app.route('/logout') + def logout(): + # remove the username from the session if its there + session.pop('username', None) + return redirect(url_for('index')) + + # set the secret key. keep this really secret: + app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT' + +The here mentioned :func:`~flask.escape` does escaping for you if you are +not using the template engine (like in this example). + +.. admonition:: How to generate good secret keys + + The problem with random is that it's hard to judge what random is. And + a secret key should be as random as possible. Your operating system + has ways to generate pretty random stuff based on a cryptographic + random generator which can be used to get such a key: + + >>> import os + >>> os.urandom(24) + '\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8' + + Just take that thing and copy/paste it into your code and you're done. + +Message Flashing +---------------- + +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. + +To flash a message use the :func:`~flask.flash` method, to get hold of the +messages you can use :func:`~flask.get_flashed_messages` which is also +available in the templates. Check out the :ref:`message-flashing-pattern` +for a full example. + +Logging +------- + +.. versionadded:: 0.3 + +Sometimes you might be in a situation where you deal with data that +should be correct, but actually is not. For example you may have some client +side code that sends an HTTP request to the server but it's obviously +malformed. This might be caused by a user tempering with the data, or the +client code failing. Most of the time, it's okay to reply with ``400 Bad +Request`` in that situation, but sometimes that won't do and the code has +to continue working. + +You may still want to log that something fishy happened. This is where +loggers come in handy. As of Flask 0.3 a logger is preconfigured for you +to use. + +Here are some example log calls:: + + app.logger.debug('A value for debugging') + app.logger.warning('A warning occurred (%d apples)', 42) + app.logger.error('An error occurred') + +The attached :attr:`~flask.Flask.logger` is a standard logging +:class:`~logging.Logger`, so head over to the official `logging +documentation <http://docs.python.org/library/logging.html>`_ for more +information. + +Hooking in WSGI Middlewares +--------------------------- + +If you want to add a WSGI middleware to your application you can wrap the +internal WSGI application. For example if you want to use one of the +middlewares from the Werkzeug package to work around bugs in lighttpd, you +can do it like this:: + + from werkzeug.contrib.fixers import LighttpdCGIRootFix + app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app) |