Using Templates and Static Assets with Flask Applications on RStudio Connect

Follow

In this example, we'll include template and static assets bundled with a Flask application for rendered pages and CSS styles.   

It's possible to deploy and manage runtime settings for Flask applications Beginning in RStudio Connect 1.8.2+

Flask prescribes a particular directory structure for serving static assets alongside an application. RStudio Connect respects this directory structure and makes it possible, if needed, to include these resources in the application bundle during deployment.

In this example, we'll step through adding this functionality to a Flask application deployed on RStudio Connect.

A more detailed getting started example with Flask and RStudio Connect is available here.

Goal 

The application will fetch and return a rendered index.html Jinja2 template when an end-user accesses the root route /.

The example will follow these steps:

  • Define application structure with index endpoint
  • Create an index.html Jinja2 template
  • Add style.css asset
  • Reference the stylesheet asset from within the template
  • Deploy the Flask application to RStudio Connect using rsconnect-python

Requirements

For this example to work, the prerequisite configurations and setup include:

rsconnect-python

If needed, rsconnect-python is available on PyPI.  To install with pip, run the following command:

pip install rsconnect-python

 

Application structure

A minimal application structure typically includes the below files for deployment to RStudio Connect using the rsconnect-python command-line interface. 

 .
├─ app.py
└─ .gitignore

 

In app.py, place the following snippet:

# app.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

The return statement in the the snippet above is a temporary placeholder. Next, we'll introduce and return a template for this view.

Templates

It is common to place templates within a templates directory that sits alongside the entry point file of the application. In this example, that file is app.py.

Following the Flask rendering templates documentation,  create a templates directory. Then, create a  index.html in the same directory.

The directory tree will now resemble:
  .
+ ├─ templates
+ │ └─ index.html
├─ app.py
└─ .gitignore
Add the index.html file into the template directory.  We'll reference this template from within our application route.
<!-- index.html -->
<html>

<head> </head>
<body class="pa">
<div class="ba">
Hello, World!
</div>
</body>
</html>

This template is a Jinja2 template and can use all of the templating features available within Jinja to customize a dynamic experience for the application. 

Now, update the application to return that template when the base endpoint is accessed.  Notice that the render_template method is now imported into the file and also referenced in the route handler.

# app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def hello_world():
    return render_template('index.html')

The application will now render the index.html template and return the output of that method to the browser when a user accesses that specific route.

Styles

Following the Flask static files documentation, create a static directory. Then, create a  style.css in that same directory.

The directory tree will now resemble:
  .
├─ templates
│ └─ index.html
+ ├─ static
+ │ └─ style.css
├─ app.py
└─ .gitignore

 Create a basic stylesheet to include in the template.  These styles will add a border and padding to the Hello, World! text in the template HTML.

// style.css
.ba {

border-style: solid;
border-width: 1px;
}

.pa {
padding: 1rem;
}

 

Update index.html to use style.css

Add the static reference in the <head> element of the HTML.  For this, we'll utilize the url_for method provided by Flask.

The url_for method will construct the correct URL that references our  default static assets directory along with the file, style.css, itself.

 <!-- index.html -->
<html>

<head>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}" />
</head>

<body class="pa">
<div class="ba">
Hello, World!
</div>
</body>
</html>

 

Deployment with Extra Files

This application can be deployed once tested locally.

Before deployment, it's recommended that a requirements.txt file is created in the working environment. This file will list all the Python packages that exist in the environment. It's good practice to validate this environment before deployment even though rsconnect-pythonwill create this file if it doesn't exist on deploy.
pip freeze > requirements.txt

The directory will now contain:

  .
├─ templates
│ └─ index.html
├─ static
│ └─ style.css
├─ app.py
├─ .gitignore
+ └─ requirements.txt

Deploy the application with the following command, substituting the server-name reference for the name of your target RStudio Connect server.  In this example, the current working directory is deployed as referenced by the . in the command.

rsconnect deploy api -n <server-name> . templates/* static/*
This command instructs rsconnect-python to include extra files along with the primary file set.  In this case,  the templates and static directory are specified.

Deployment with Git 

rsconnect-python can also generate a manifest file that captures information about the environment for use with Git or future deployment.

The command below will generate a manifest.json file in the working directory that contains project environment information including the specified files.

rsconnect write-manifest api . templates/* static/*
The manifest.json can be committed to Git and used to deploy the application to RStudio Connect using a Git backed deployment workflow.

See also

Additional examples and walkthroughs of getting started with Flask application deployment on RStudio Connect:

 

 

Comments