Customize Django for Platform.sh
Back to home
On this page
Now that your code contains all of the configuration to deploy on Platform.sh, it’s time to make your Django site itself ready to run on a Platform.sh environment. A number of additional steps are either required or recommended, depending on how much you want to optimize your site.
Optional: Set up the Config Reader
You can get all information about a deployed environment, including how to connect to services, through environment variables. Your app can access these variables.
In all of the following examples, you can replace retrieving and decoding environment variables with this library.
Django configuration
Most configuration for Django, such as service credentials, is done in a settings.py
file.
You can see an example of a complete settings file in the Django template.
The example file configures app settings and credentials for connecting to a PostgreSQL database. The environment variables defined there enable Django apps to remain independent of their environment.
The example file itself contains a lot of settings, the most important of which are highlighted here to show where you could modify your code.
Allowed hosts
ALLOWED_HOSTS
defines the host names that your Django site can serve.
It’s where you define localhost
and also your site’s primary domain.
On Platform.sh, every branch or pull request you create can become an active environment:
a deployed site where you can test changes.
The environment is given a URL that ends with .platform.site
.
To allow your site to serve these environment, add this suffix to ALLOWED_HOSTS
.
ALLOWED_HOSTS = [
'localhost',
'127.0.0.1',
'.platformsh.site',
]
Decoding variables
Platform.sh environment variables, which contain information on deployed environments, are often obscured.
For example, PLATFORM_RELATIONSHIPS
, which contains credentials to connect to services, is a base64-encoded JSON object.
The example Django configuration file has a decode
helper function to help with these variables.
Alternatively, you can use the Platform.sh Config Reader.
#################################################################################
# Platform.sh-specific configuration
# Helper function for decoding base64-encoded JSON variables.
def decode(variable):
"""Decodes a Platform.sh environment variable.
Args:
variable (string):
Base64-encoded JSON (the content of an environment variable).
Returns:
An dict (if representing a JSON object), or a scalar type.
Raises:
JSON decoding error.
"""
try:
if sys.version_info[1] > 5:
return json.loads(base64.b64decode(variable))
else:
return json.loads(base64.b64decode(variable).decode('utf-8'))
except json.decoder.JSONDecodeError:
print('Error decoding JSON, code %d', json.decoder.JSONDecodeError)
Handling overrides
Once you have a way to decode variables,
you can use them to override settings based on the environment.
The following example uses the decode
function to set access to the one service defined in this example,
a PostgreSQL database.
# This variable must always match the primary database relationship name,
# configured in .platform.app.yaml.
PLATFORMSH_DB_RELATIONSHIP="database"
# Import some Platform.sh settings from the environment.
# The following block is only applied within Platform.sh environments
# That is, only when this Platform.sh variable is defined
if (os.getenv('PLATFORM_APPLICATION_NAME') is not None):
DEBUG = False
# Redefine the static root based on the Platform.sh directory
# See https://docs.djangoproject.com/en/4.1/ref/settings/#static-root
if (os.getenv('PLATFORM_APP_DIR') is not None):
STATIC_ROOT = os.path.join(os.getenv('PLATFORM_APP_DIR'), 'static')
# PLATFORM_PROJECT_ENTROPY is unique to your project
# Use it to define define Django's SECRET_KEY
# See https://docs.djangoproject.com/en/4.1/ref/settings/#secret-key
if (os.getenv('PLATFORM_PROJECT_ENTROPY') is not None):
SECRET_KEY = os.getenv('PLATFORM_PROJECT_ENTROPY')
# Database service configuration, post-build only
# As services aren't available during the build
if (os.getenv('PLATFORM_ENVIRONMENT') is not None):
platformRelationships = decode(os.getenv('PLATFORM_RELATIONSHIPS'))
db_settings = platformRelationships[PLATFORMSH_DB_RELATIONSHIP][0]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': db_settings['path'],
'USER': db_settings['username'],
'PASSWORD': db_settings['password'],
'HOST': db_settings['host'],
'PORT': db_settings['port'],
},
'sqlite': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
As noted in comments in the example, services on Platform.sh (like PostgreSQL) aren’t yet available during the build. This it enables the environment-independent builds that make the Platform.sh inheritance model possible.
For this reason, when defining a service connection, you need to overwrite the settings during the deploy phase.
You can determine the deploy phase using the PLATFORM_ENVIRONMENT
variable, which is only available at deploy time.
.environment
and Poetry
source .environment
is run in the app root
when a project starts, before cron commands are run, and when you log into an environment over SSH.
So you can use the .environment
file to make further changes to environment variables before the app runs,
including modifying the system $PATH
and other shell level customizations.
Django projects like this example using Pip or Pipenv don’t need a .environment
file to run.
Using Poetry requires additional configuration to ensure that Poetry can be called during the deploy phase and SSH sessions.
# Updates PATH when Poetry is used, making it available during deploys and SSH.
if [ -n "$POETRY_VERSION" ]; then
export PATH="/app/.local/bin:$PATH"
fi
If you have other environment variables your app depends on that aren’t sensitive and so can be committed to Git,
you can include them in the .environment
file