forked from orbit-oss/flask
refactor or remove old docs (#4748)
This commit is contained in:
parent
45b2c99c1f
commit
a0458efef6
10 changed files with 43 additions and 681 deletions
|
|
@ -1,46 +0,0 @@
|
|||
Foreword for Experienced Programmers
|
||||
====================================
|
||||
|
||||
Thread-Locals in Flask
|
||||
----------------------
|
||||
|
||||
One of the design decisions in Flask was that simple tasks should be simple;
|
||||
they should not take a lot of code and yet they should not limit you. Because
|
||||
of that, Flask has a few design choices that some people might find
|
||||
surprising or unorthodox. For example, Flask uses thread-local objects
|
||||
internally so that you don’t have to pass objects around from
|
||||
function to function within a request in order to stay threadsafe.
|
||||
This approach is convenient, but requires a valid
|
||||
request context for dependency injection or when attempting to reuse code which
|
||||
uses a value pegged to the request. The Flask project is honest about
|
||||
thread-locals, does not hide them, and calls out in the code and documentation
|
||||
where they are used.
|
||||
|
||||
Develop for the Web with Caution
|
||||
--------------------------------
|
||||
|
||||
Always keep security in mind when building web applications.
|
||||
|
||||
If you write a web application, you are probably allowing users to register
|
||||
and leave their data on your server. The users are entrusting you with data.
|
||||
And even if you are the only user that might leave data in your application,
|
||||
you still want that data to be stored securely.
|
||||
|
||||
Unfortunately, there are many ways the security of a web application can be
|
||||
compromised. Flask protects you against one of the most common security
|
||||
problems of modern web applications: cross-site scripting (XSS). Unless you
|
||||
deliberately mark insecure HTML as secure, Flask and the underlying Jinja2
|
||||
template engine have you covered. But there are many more ways to cause
|
||||
security problems.
|
||||
|
||||
The documentation will warn you about aspects of web development that require
|
||||
attention to security. Some of these security concerns are far more complex
|
||||
than one might think, and we all sometimes underestimate the likelihood that a
|
||||
vulnerability will be exploited - until a clever attacker figures out a way to
|
||||
exploit our applications. And don't think that your application is not
|
||||
important enough to attract an attacker. Depending on the kind of attack,
|
||||
chances are that automated bots are probing for ways to fill your database with
|
||||
spam, links to malicious software, and the like.
|
||||
|
||||
Flask is no different from any other framework in that you the developer must
|
||||
build with caution, watching for exploits when building to your requirements.
|
||||
|
|
@ -394,13 +394,11 @@ The following configuration values are used internally by Flask:
|
|||
Configuring from Python Files
|
||||
-----------------------------
|
||||
|
||||
Configuration becomes more useful if you can store it in a separate file,
|
||||
ideally located outside the actual application package. This makes
|
||||
packaging and distributing your application possible via various package
|
||||
handling tools (:doc:`/patterns/distribute`) and finally modifying the
|
||||
configuration file afterwards.
|
||||
Configuration becomes more useful if you can store it in a separate file, ideally
|
||||
located outside the actual application package. You can deploy your application, then
|
||||
separately configure it for the specific deployment.
|
||||
|
||||
So a common pattern is this::
|
||||
A common pattern is this::
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object('yourapplication.default_settings')
|
||||
|
|
@ -692,10 +690,8 @@ your configuration files. However here a list of good recommendations:
|
|||
code at all. If you are working often on different projects you can
|
||||
even create your own script for sourcing that activates a virtualenv
|
||||
and exports the development configuration for you.
|
||||
- Use a tool like `fabric`_ in production to push code and
|
||||
configurations separately to the production server(s). For some
|
||||
details about how to do that, head over to the
|
||||
:doc:`/patterns/fabric` pattern.
|
||||
- Use a tool like `fabric`_ to push code and configuration separately
|
||||
to the production server(s).
|
||||
|
||||
.. _fabric: https://www.fabfile.org/
|
||||
|
||||
|
|
|
|||
|
|
@ -130,9 +130,25 @@ being present. You can easily use your own templating language, but an
|
|||
extension could still depend on Jinja itself.
|
||||
|
||||
|
||||
Micro with Dependencies
|
||||
What does "micro" mean?
|
||||
-----------------------
|
||||
|
||||
“Micro” does not mean that your whole web application has to fit into a single
|
||||
Python file (although it certainly can), nor does it mean that Flask is lacking
|
||||
in functionality. The "micro" in microframework means Flask aims to keep the
|
||||
core simple but extensible. Flask won't make many decisions for you, such as
|
||||
what database to use. Those decisions that it does make, such as what
|
||||
templating engine to use, are easy to change. Everything else is up to you, so
|
||||
that Flask can be everything you need and nothing you don't.
|
||||
|
||||
By default, Flask does not include a database abstraction layer, form
|
||||
validation or anything else where different libraries already exist that can
|
||||
handle that. Instead, Flask supports extensions to add such functionality to
|
||||
your application as if it was implemented in Flask itself. Numerous extensions
|
||||
provide database integration, form validation, upload handling, various open
|
||||
authentication technologies, and more. Flask may be "micro", but it's ready for
|
||||
production use on a variety of needs.
|
||||
|
||||
Why does Flask call itself a microframework and yet it depends on two
|
||||
libraries (namely Werkzeug and Jinja2). Why shouldn't it? If we look
|
||||
over to the Ruby side of web development there we have a protocol very
|
||||
|
|
@ -201,5 +217,12 @@ requirements and Flask could not meet those if it would force any of this
|
|||
into the core. The majority of web applications will need a template
|
||||
engine in some sort. However not every application needs a SQL database.
|
||||
|
||||
As your codebase grows, you are free to make the design decisions appropriate
|
||||
for your project. Flask will continue to provide a very simple glue layer to
|
||||
the best that Python has to offer. You can implement advanced patterns in
|
||||
SQLAlchemy or another database tool, introduce non-relational data persistence
|
||||
as appropriate, and take advantage of framework-agnostic tools built for WSGI,
|
||||
the Python web interface.
|
||||
|
||||
The idea of Flask is to build a good foundation for all applications.
|
||||
Everything else is up to you or extensions.
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
Foreword
|
||||
========
|
||||
|
||||
Read this before you get started with Flask. This hopefully answers some
|
||||
questions about the purpose and goals of the project, and when you
|
||||
should or should not be using it.
|
||||
|
||||
What does "micro" mean?
|
||||
-----------------------
|
||||
|
||||
“Micro” does not mean that your whole web application has to fit into a single
|
||||
Python file (although it certainly can), nor does it mean that Flask is lacking
|
||||
in functionality. The "micro" in microframework means Flask aims to keep the
|
||||
core simple but extensible. Flask won't make many decisions for you, such as
|
||||
what database to use. Those decisions that it does make, such as what
|
||||
templating engine to use, are easy to change. Everything else is up to you, so
|
||||
that Flask can be everything you need and nothing you don't.
|
||||
|
||||
By default, Flask does not include a database abstraction layer, form
|
||||
validation or anything else where different libraries already exist that can
|
||||
handle that. Instead, Flask supports extensions to add such functionality to
|
||||
your application as if it was implemented in Flask itself. Numerous extensions
|
||||
provide database integration, form validation, upload handling, various open
|
||||
authentication technologies, and more. Flask may be "micro", but it's ready for
|
||||
production use on a variety of needs.
|
||||
|
||||
Configuration and Conventions
|
||||
-----------------------------
|
||||
|
||||
Flask has many configuration values, with sensible defaults, and a few
|
||||
conventions when getting started. By convention, templates and static
|
||||
files are stored in subdirectories within the application's Python
|
||||
source tree, with the names :file:`templates` and :file:`static`
|
||||
respectively. While this can be changed, you usually don't have to,
|
||||
especially when getting started.
|
||||
|
||||
Growing with Flask
|
||||
------------------
|
||||
|
||||
Once you have Flask up and running, you'll find a variety of extensions
|
||||
available in the community to integrate your project for production.
|
||||
|
||||
As your codebase grows, you are free to make the design decisions appropriate
|
||||
for your project. Flask will continue to provide a very simple glue layer to
|
||||
the best that Python has to offer. You can implement advanced patterns in
|
||||
SQLAlchemy or another database tool, introduce non-relational data persistence
|
||||
as appropriate, and take advantage of framework-agnostic tools built for WSGI,
|
||||
the Python web interface.
|
||||
|
||||
Flask includes many hooks to customize its behavior. Should you need
|
||||
more customization, the Flask class is built for subclassing. If you are
|
||||
curious about the Flask design principles, head over to the section
|
||||
about :doc:`design`.
|
||||
206
docs/htmlfaq.rst
206
docs/htmlfaq.rst
|
|
@ -1,206 +0,0 @@
|
|||
HTML/XHTML FAQ
|
||||
==============
|
||||
|
||||
The Flask documentation and example applications are using HTML5. You
|
||||
may notice that in many situations, when end tags are optional they are
|
||||
not used, so that the HTML is cleaner and faster to load. Because there
|
||||
is much confusion about HTML and XHTML among developers, this document tries
|
||||
to answer some of the major questions.
|
||||
|
||||
|
||||
History of XHTML
|
||||
----------------
|
||||
|
||||
For a while, it appeared that HTML was about to be replaced by XHTML.
|
||||
However, barely any websites on the Internet are actual XHTML (which is
|
||||
HTML processed using XML rules). There are a couple of major reasons
|
||||
why this is the case. One of them is Internet Explorer's lack of proper
|
||||
XHTML support. The XHTML spec states that XHTML must be served with the MIME
|
||||
type :mimetype:`application/xhtml+xml`, but Internet Explorer refuses
|
||||
to read files with that MIME type.
|
||||
While it is relatively easy to configure Web servers to serve XHTML properly,
|
||||
few people do. This is likely because properly using XHTML can be quite
|
||||
painful.
|
||||
|
||||
One of the most important causes of pain is XML's draconian (strict and
|
||||
ruthless) error handling. When an XML parsing error is encountered,
|
||||
the browser is supposed to show the user an ugly error message, instead
|
||||
of attempting to recover from the error and display what it can. Most of
|
||||
the (X)HTML generation on the web is based on non-XML template engines
|
||||
(such as Jinja, the one used in Flask) which do not protect you from
|
||||
accidentally creating invalid XHTML. There are XML based template engines,
|
||||
such as Kid and the popular Genshi, but they often come with a larger
|
||||
runtime overhead and are not as straightforward to use because they have
|
||||
to obey XML rules.
|
||||
|
||||
The majority of users, however, assumed they were properly using XHTML.
|
||||
They wrote an XHTML doctype at the top of the document and self-closed all
|
||||
the necessary tags (``<br>`` becomes ``<br/>`` or ``<br></br>`` in XHTML).
|
||||
However, even if the document properly validates as XHTML, what really
|
||||
determines XHTML/HTML processing in browsers is the MIME type, which as
|
||||
said before is often not set properly. So the valid XHTML was being treated
|
||||
as invalid HTML.
|
||||
|
||||
XHTML also changed the way JavaScript is used. To properly work with XHTML,
|
||||
programmers have to use the namespaced DOM interface with the XHTML
|
||||
namespace to query for HTML elements.
|
||||
|
||||
History of HTML5
|
||||
----------------
|
||||
|
||||
Development of the HTML5 specification was started in 2004 under the name
|
||||
"Web Applications 1.0" by the Web Hypertext Application Technology Working
|
||||
Group, or WHATWG (which was formed by the major browser vendors Apple,
|
||||
Mozilla, and Opera) with the goal of writing a new and improved HTML
|
||||
specification, based on existing browser behavior instead of unrealistic
|
||||
and backwards-incompatible specifications.
|
||||
|
||||
For example, in HTML4 ``<title/Hello/`` theoretically parses exactly the
|
||||
same as ``<title>Hello</title>``. However, since people were using
|
||||
XHTML-like tags along the lines of ``<link />``, browser vendors implemented
|
||||
the XHTML syntax over the syntax defined by the specification.
|
||||
|
||||
In 2007, the specification was adopted as the basis of a new HTML
|
||||
specification under the umbrella of the W3C, known as HTML5. Currently,
|
||||
it appears that XHTML is losing traction, as the XHTML 2 working group has
|
||||
been disbanded and HTML5 is being implemented by all major browser vendors.
|
||||
|
||||
HTML versus XHTML
|
||||
-----------------
|
||||
|
||||
The following table gives you a quick overview of features available in
|
||||
HTML 4.01, XHTML 1.1 and HTML5. (XHTML 1.0 is not included, as it was
|
||||
superseded by XHTML 1.1 and the barely-used XHTML5.)
|
||||
|
||||
.. tabularcolumns:: |p{9cm}|p{2cm}|p{2cm}|p{2cm}|
|
||||
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
| | HTML4.01 | XHTML1.1 | HTML5 |
|
||||
+=========================================+==========+==========+==========+
|
||||
| ``<tag/value/`` == ``<tag>value</tag>`` | |Y| [1]_ | |N| | |N| |
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
| ``<br/>`` supported | |N| | |Y| | |Y| [2]_ |
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
| ``<script/>`` supported | |N| | |Y| | |N| |
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
| should be served as `text/html` | |Y| | |N| [3]_ | |Y| |
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
| should be served as | |N| | |Y| | |N| |
|
||||
| `application/xhtml+xml` | | | |
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
| strict error handling | |N| | |Y| | |N| |
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
| inline SVG | |N| | |Y| | |Y| |
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
| inline MathML | |N| | |Y| | |Y| |
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
| ``<video>`` tag | |N| | |N| | |Y| |
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
| ``<audio>`` tag | |N| | |N| | |Y| |
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
| New semantic tags like ``<article>`` | |N| | |N| | |Y| |
|
||||
+-----------------------------------------+----------+----------+----------+
|
||||
|
||||
.. [1] This is an obscure feature inherited from SGML. It is usually not
|
||||
supported by browsers, for reasons detailed above.
|
||||
.. [2] This is for compatibility with server code that generates XHTML for
|
||||
tags such as ``<br>``. It should not be used in new code.
|
||||
.. [3] XHTML 1.0 is the last XHTML standard that allows to be served
|
||||
as `text/html` for backwards compatibility reasons.
|
||||
|
||||
.. |Y| image:: _static/yes.png
|
||||
:alt: Yes
|
||||
.. |N| image:: _static/no.png
|
||||
:alt: No
|
||||
|
||||
What does "strict" mean?
|
||||
------------------------
|
||||
|
||||
HTML5 has strictly defined parsing rules, but it also specifies exactly
|
||||
how a browser should react to parsing errors - unlike XHTML, which simply
|
||||
states parsing should abort. Some people are confused by apparently
|
||||
invalid syntax that still generates the expected results (for example,
|
||||
missing end tags or unquoted attribute values).
|
||||
|
||||
Some of these work because of the lenient error handling most browsers use
|
||||
when they encounter a markup error, others are actually specified. The
|
||||
following constructs are optional in HTML5 by standard, but have to be
|
||||
supported by browsers:
|
||||
|
||||
- Wrapping the document in an ``<html>`` tag
|
||||
- Wrapping header elements in ``<head>`` or the body elements in
|
||||
``<body>``
|
||||
- Closing the ``<p>``, ``<li>``, ``<dt>``, ``<dd>``, ``<tr>``,
|
||||
``<td>``, ``<th>``, ``<tbody>``, ``<thead>``, or ``<tfoot>`` tags.
|
||||
- Quoting attributes, so long as they contain no whitespace or
|
||||
special characters (like ``<``, ``>``, ``'``, or ``"``).
|
||||
- Requiring boolean attributes to have a value.
|
||||
|
||||
This means the following page in HTML5 is perfectly valid:
|
||||
|
||||
.. sourcecode:: html
|
||||
|
||||
<!doctype html>
|
||||
<title>Hello HTML5</title>
|
||||
<div class=header>
|
||||
<h1>Hello HTML5</h1>
|
||||
<p class=tagline>HTML5 is awesome
|
||||
</div>
|
||||
<ul class=nav>
|
||||
<li><a href=/index>Index</a>
|
||||
<li><a href=/downloads>Downloads</a>
|
||||
<li><a href=/about>About</a>
|
||||
</ul>
|
||||
<div class=body>
|
||||
<h2>HTML5 is probably the future</h2>
|
||||
<p>
|
||||
There might be some other things around but in terms of
|
||||
browser vendor support, HTML5 is hard to beat.
|
||||
<dl>
|
||||
<dt>Key 1
|
||||
<dd>Value 1
|
||||
<dt>Key 2
|
||||
<dd>Value 2
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
|
||||
New technologies in HTML5
|
||||
-------------------------
|
||||
|
||||
HTML5 adds many new features that make Web applications easier to write
|
||||
and to use.
|
||||
|
||||
- The ``<audio>`` and ``<video>`` tags provide a way to embed audio and
|
||||
video without complicated add-ons like QuickTime or Flash.
|
||||
- Semantic elements like ``<article>``, ``<header>``, ``<nav>``, and
|
||||
``<time>`` that make content easier to understand.
|
||||
- The ``<canvas>`` tag, which supports a powerful drawing API, reducing
|
||||
the need for server-generated images to present data graphically.
|
||||
- New form control types like ``<input type="date">`` that allow user
|
||||
agents to make entering and validating values easier.
|
||||
- Advanced JavaScript APIs like Web Storage, Web Workers, Web Sockets,
|
||||
geolocation, and offline applications.
|
||||
|
||||
Many other features have been added, as well. A good guide to new features
|
||||
in HTML5 is Mark Pilgrim's book, `Dive Into HTML5`_.
|
||||
Not all of them are supported in browsers yet, however, so use caution.
|
||||
|
||||
.. _Dive Into HTML5: https://diveintohtml5.info/
|
||||
|
||||
What should be used?
|
||||
--------------------
|
||||
|
||||
Currently, the answer is HTML5. There are very few reasons to use XHTML
|
||||
considering the latest developments in Web browsers. To summarize the
|
||||
reasons given above:
|
||||
|
||||
- Internet Explorer has poor support for XHTML.
|
||||
- Many JavaScript libraries also do not support XHTML, due to the more
|
||||
complicated namespacing API it requires.
|
||||
- HTML5 adds several new features, including semantic tags and the
|
||||
long-awaited ``<audio>`` and ``<video>`` tags.
|
||||
- It has the support of most browser vendors behind it.
|
||||
- It is much easier to write, and more compact.
|
||||
|
||||
For most applications, it is undoubtedly better to use HTML5 than XHTML.
|
||||
|
|
@ -29,15 +29,14 @@ toolkit. The documentation for these libraries can be found at:
|
|||
User's Guide
|
||||
------------
|
||||
|
||||
This part of the documentation, which is mostly prose, begins with some
|
||||
background information about Flask, then focuses on step-by-step
|
||||
instructions for web development with Flask.
|
||||
Flask provides configuration and conventions, with sensible defaults, to get started.
|
||||
This section of the documentation explains the different parts of the Flask framework
|
||||
and how they can be used, customized, and extended. Beyond Flask itself, look for
|
||||
community-maintained extensions to add even more functionality.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
foreword
|
||||
advanced_foreword
|
||||
installation
|
||||
quickstart
|
||||
tutorial/index
|
||||
|
|
@ -57,6 +56,7 @@ instructions for web development with Flask.
|
|||
server
|
||||
shell
|
||||
patterns/index
|
||||
security
|
||||
deploying/index
|
||||
async-await
|
||||
|
||||
|
|
@ -76,14 +76,10 @@ method, this part of the documentation is for you.
|
|||
Additional Notes
|
||||
----------------
|
||||
|
||||
Design notes, legal information and changelog are here for the interested.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
design
|
||||
htmlfaq
|
||||
security
|
||||
extensiondev
|
||||
contributing
|
||||
license
|
||||
|
|
|
|||
|
|
@ -1,170 +0,0 @@
|
|||
Deploying with Setuptools
|
||||
=========================
|
||||
|
||||
`Setuptools`_, is an extension library that is commonly used to
|
||||
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:
|
||||
|
||||
- **support for dependencies**: a library or application can declare a
|
||||
list of other libraries it depends on which will be installed
|
||||
automatically for you.
|
||||
- **package registry**: 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" that another package can hook into to extend the
|
||||
other package.
|
||||
- **installation manager**: :command:`pip` can install other libraries for you.
|
||||
|
||||
Flask itself, and all the libraries you can find on PyPI are distributed with
|
||||
either setuptools or distutils.
|
||||
|
||||
In this case we assume your application is called
|
||||
:file:`yourapplication.py` and you are not using a module, but a
|
||||
package. If you have not yet converted your application into a package,
|
||||
head over to :doc:`packages` to see how this can be done.
|
||||
|
||||
A working deployment with setuptools is the first step into more complex
|
||||
and more automated deployment scenarios. If you want to fully automate
|
||||
the process, also read the :doc:`fabric` chapter.
|
||||
|
||||
Basic Setup Script
|
||||
------------------
|
||||
|
||||
Because you have Flask installed, you have setuptools available on your system.
|
||||
Flask already depends upon setuptools.
|
||||
|
||||
Standard disclaimer applies: :ref:`use a virtualenv
|
||||
<install-create-env>`.
|
||||
|
||||
Your setup code always goes into a file named :file:`setup.py` 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.
|
||||
|
||||
A basic :file:`setup.py` file for a Flask application looks like this::
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='Your Application',
|
||||
version='1.0',
|
||||
long_description=__doc__,
|
||||
packages=['yourapplication'],
|
||||
include_package_data=True,
|
||||
zip_safe=False,
|
||||
install_requires=['Flask']
|
||||
)
|
||||
|
||||
Please keep in mind that you have to list subpackages explicitly. If you
|
||||
want setuptools to lookup the packages for you automatically, you can use
|
||||
the ``find_packages`` function::
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
setup(
|
||||
...
|
||||
packages=find_packages()
|
||||
)
|
||||
|
||||
Most parameters to the ``setup`` function should be self explanatory,
|
||||
``include_package_data`` and ``zip_safe`` might not be.
|
||||
``include_package_data`` tells setuptools to look for a :file:`MANIFEST.in` 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 :ref:`distributing-resources`). The ``zip_safe`` 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.
|
||||
|
||||
|
||||
Tagging Builds
|
||||
--------------
|
||||
|
||||
It is useful to distinguish between release and development builds. Add a
|
||||
:file:`setup.cfg` file to configure these options. ::
|
||||
|
||||
[egg_info]
|
||||
tag_build = .dev
|
||||
tag_date = 1
|
||||
|
||||
[aliases]
|
||||
release = egg_info -Db ''
|
||||
|
||||
Running ``python setup.py sdist`` will create a development package
|
||||
with ".dev" and the current date appended: ``flaskr-1.0.dev20160314.tar.gz``.
|
||||
Running ``python setup.py release sdist`` will create a release package
|
||||
with only the version: ``flaskr-1.0.tar.gz``.
|
||||
|
||||
|
||||
.. _distributing-resources:
|
||||
|
||||
Distributing Resources
|
||||
----------------------
|
||||
|
||||
If you try to install the package you just created, you will notice that
|
||||
folders like :file:`static` or :file:`templates` are not installed for you. The
|
||||
reason for this is that setuptools does not know which files to add for
|
||||
you. What you should do, is to create a :file:`MANIFEST.in` file next to your
|
||||
:file:`setup.py` file. This file lists all the files that should be added to
|
||||
your tarball::
|
||||
|
||||
recursive-include yourapplication/templates *
|
||||
recursive-include yourapplication/static *
|
||||
|
||||
Don't forget that even if you enlist them in your :file:`MANIFEST.in` file, they
|
||||
won't be installed for you unless you set the `include_package_data`
|
||||
parameter of the ``setup`` function to ``True``!
|
||||
|
||||
|
||||
Declaring Dependencies
|
||||
----------------------
|
||||
|
||||
Dependencies are declared in the ``install_requires`` parameter as a 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::
|
||||
|
||||
install_requires=[
|
||||
'Flask>=0.2',
|
||||
'SQLAlchemy>=0.6',
|
||||
'BrokenPackage>=0.7,<=1.0'
|
||||
]
|
||||
|
||||
As mentioned earlier, 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 do it as if there was a PyPI entry and provide a list of
|
||||
alternative locations where setuptools should look for tarballs::
|
||||
|
||||
dependency_links=['http://example.com/yourfiles']
|
||||
|
||||
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 setuptools will find the files. If you have an internal company
|
||||
server that contains the packages, provide the URL to that server.
|
||||
|
||||
|
||||
Installing / Developing
|
||||
-----------------------
|
||||
|
||||
To install your application (ideally into a virtualenv) just run the
|
||||
:file:`setup.py` script with the ``install`` parameter. It will install your
|
||||
application into the virtualenv's site-packages folder and also download
|
||||
and install all dependencies::
|
||||
|
||||
$ python setup.py install
|
||||
|
||||
If you are developing on the package and also want the requirements to be
|
||||
installed, you can use the ``develop`` command instead::
|
||||
|
||||
$ python setup.py develop
|
||||
|
||||
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 ``install`` again after each change.
|
||||
|
||||
|
||||
.. _pip: https://pypi.org/project/pip/
|
||||
.. _Setuptools: https://pypi.org/project/setuptools/
|
||||
|
|
@ -1,184 +0,0 @@
|
|||
Deploying with Fabric
|
||||
=====================
|
||||
|
||||
`Fabric`_ 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 (:doc:`packages`) and a good concept for
|
||||
configurations (:doc:`/config`) it is very easy to deploy Flask
|
||||
applications to external servers.
|
||||
|
||||
Before we get started, here a quick checklist of things we have to ensure
|
||||
upfront:
|
||||
|
||||
- Fabric 1.0 has to be installed locally. This tutorial assumes the
|
||||
latest version of Fabric.
|
||||
- The application already has to be a package and requires a working
|
||||
:file:`setup.py` file (:doc:`distribute`).
|
||||
- In the following example we are using `mod_wsgi` for the remote
|
||||
servers. You can of course use your own favourite server there, but
|
||||
for this example we chose Apache + `mod_wsgi` because it's very easy
|
||||
to setup and has a simple way to reload applications without root
|
||||
access.
|
||||
|
||||
Creating the first Fabfile
|
||||
--------------------------
|
||||
|
||||
A fabfile is what controls what Fabric executes. It is named :file:`fabfile.py`
|
||||
and executed by the `fab` command. All the functions defined in that file
|
||||
will show up as `fab` 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.
|
||||
|
||||
This is a basic first example that has the ability to upload the current
|
||||
source code to the server and install it into a pre-existing
|
||||
virtual environment::
|
||||
|
||||
from fabric.api import *
|
||||
|
||||
# the user to use for the remote commands
|
||||
env.user = 'appuser'
|
||||
# the servers where the commands are executed
|
||||
env.hosts = ['server1.example.com', 'server2.example.com']
|
||||
|
||||
def pack():
|
||||
# build the package
|
||||
local('python setup.py sdist --formats=gztar', capture=False)
|
||||
|
||||
def deploy():
|
||||
# figure out the package name and version
|
||||
dist = local('python setup.py --fullname', capture=True).strip()
|
||||
filename = f'{dist}.tar.gz'
|
||||
|
||||
# upload the package to the temporary folder on the server
|
||||
put(f'dist/{filename}', f'/tmp/{filename}')
|
||||
|
||||
# install the package in the application's virtualenv with pip
|
||||
run(f'/var/www/yourapplication/env/bin/pip install /tmp/{filename}')
|
||||
|
||||
# remove the uploaded package
|
||||
run(f'rm -r /tmp/{filename}')
|
||||
|
||||
# touch the .wsgi file to trigger a reload in mod_wsgi
|
||||
run('touch /var/www/yourapplication.wsgi')
|
||||
|
||||
Running Fabfiles
|
||||
----------------
|
||||
|
||||
Now how do you execute that fabfile? You use the `fab` command. To
|
||||
deploy the current version of the code on the remote server you would use
|
||||
this command::
|
||||
|
||||
$ fab pack deploy
|
||||
|
||||
However this requires that our server already has the
|
||||
:file:`/var/www/yourapplication` folder created and
|
||||
:file:`/var/www/yourapplication/env` to be a virtual environment. Furthermore
|
||||
are we not creating the configuration or ``.wsgi`` file on the server. So
|
||||
how do we bootstrap a new server into our infrastructure?
|
||||
|
||||
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
|
||||
`setup` or `bootstrap` and then pass the servername explicitly on the
|
||||
command line::
|
||||
|
||||
$ fab -H newserver.example.com bootstrap
|
||||
|
||||
To setup a new server you would roughly do these steps:
|
||||
|
||||
1. Create the directory structure in :file:`/var/www`::
|
||||
|
||||
$ mkdir /var/www/yourapplication
|
||||
$ cd /var/www/yourapplication
|
||||
$ virtualenv --distribute env
|
||||
|
||||
2. Upload a new :file:`application.wsgi` file to the server and the
|
||||
configuration file for the application (eg: :file:`application.cfg`)
|
||||
|
||||
3. Create a new Apache config for ``yourapplication`` and activate it.
|
||||
Make sure to activate watching for changes of the ``.wsgi`` file so
|
||||
that we can automatically reload the application by touching it.
|
||||
See :doc:`/deploying/mod_wsgi`.
|
||||
|
||||
So now the question is, where do the :file:`application.wsgi` and
|
||||
:file:`application.cfg` files come from?
|
||||
|
||||
The WSGI File
|
||||
-------------
|
||||
|
||||
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::
|
||||
|
||||
import os
|
||||
os.environ['YOURAPPLICATION_CONFIG'] = '/var/www/yourapplication/application.cfg'
|
||||
from yourapplication import app
|
||||
|
||||
The application itself then has to initialize itself like this to look for
|
||||
the config at that environment variable::
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config.from_object('yourapplication.default_config')
|
||||
app.config.from_envvar('YOURAPPLICATION_CONFIG')
|
||||
|
||||
This approach is explained in detail in the :doc:`/config` section of the
|
||||
documentation.
|
||||
|
||||
The Configuration File
|
||||
----------------------
|
||||
|
||||
Now as mentioned above, the application will find the correct
|
||||
configuration file by looking up the ``YOURAPPLICATION_CONFIG`` 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.
|
||||
|
||||
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: :file:`/var/www/yourapplication`).
|
||||
|
||||
Either way, in our case here we only expect one or two servers and we can
|
||||
upload them ahead of time by hand.
|
||||
|
||||
|
||||
First Deployment
|
||||
----------------
|
||||
|
||||
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::
|
||||
|
||||
$ fab pack deploy
|
||||
|
||||
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 :file:`setup.py` file we
|
||||
will automatically pull in the required libraries into our virtual
|
||||
environment.
|
||||
|
||||
Next Steps
|
||||
----------
|
||||
|
||||
From that point onwards there is so much that can be done to make
|
||||
deployment actually fun:
|
||||
|
||||
- Create a `bootstrap` command that initializes new servers. It could
|
||||
initialize a new virtual environment, setup apache appropriately etc.
|
||||
- Put configuration files into a separate version control repository
|
||||
and symlink the active configs into place.
|
||||
- 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.
|
||||
- hook in testing functionality so that you can deploy to an external
|
||||
server and run the test suite.
|
||||
|
||||
Working with Fabric is fun and you will notice that it's quite magical to
|
||||
type ``fab deploy`` and see your application being deployed automatically
|
||||
to one or more remote servers.
|
||||
|
||||
|
||||
.. _Fabric: https://www.fabfile.org/
|
||||
|
|
@ -19,8 +19,6 @@ collected in the following pages.
|
|||
appfactories
|
||||
appdispatch
|
||||
urlprocessors
|
||||
distribute
|
||||
fabric
|
||||
sqlite3
|
||||
sqlalchemy
|
||||
fileuploads
|
||||
|
|
|
|||
|
|
@ -357,6 +357,14 @@ cumbersome because you have to do the HTML escaping on your own to keep
|
|||
the application secure. Because of that Flask configures the `Jinja2
|
||||
<https://palletsprojects.com/p/jinja/>`_ template engine for you automatically.
|
||||
|
||||
Templates can be used to generate any type of text file. For web applications, you'll
|
||||
primarily be generating HTML pages, but you can also generate markdown, plain text for
|
||||
emails, any anything else.
|
||||
|
||||
For a reference to HTML, CSS, and other web APIs, use the `MDN Web Docs`_.
|
||||
|
||||
.. _MDN Web Docs: https://developer.mozilla.org/
|
||||
|
||||
To render a template you can use the :func:`~flask.render_template`
|
||||
method. All you have to do is provide the name of the template and the
|
||||
variables you want to pass to the template engine as keyword arguments.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue