Merge branch '2.2.x'

This commit is contained in:
David Lord 2022-08-05 11:35:36 -07:00
commit 87584e89fe
No known key found for this signature in database
GPG key ID: 7A1C87E3F5BC42A8
11 changed files with 44 additions and 682 deletions

View file

@ -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 dont 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.

View file

@ -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/

View file

@ -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.

View file

@ -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`.

View file

@ -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.

View file

@ -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

View file

@ -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/

View file

@ -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/

View file

@ -19,8 +19,6 @@ collected in the following pages.
appfactories
appdispatch
urlprocessors
distribute
fabric
sqlite3
sqlalchemy
fileuploads

View file

@ -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.

View file

@ -954,7 +954,7 @@ def shell_command() -> None:
banner = (
f"Python {sys.version} on {sys.platform}\n"
f"App: {current_app.import_name} [{current_app.env}]\n"
f"App: {current_app.import_name}\n"
f"Instance: {current_app.instance_path}"
)
ctx: dict = {}