Django framework extension

The django-framework extension includes configuration options customised for a Django application. This document describes all the keys that a user may interact with.

Tip

If you’d like to see the full contents contributed by this extension, see How to manage extensions.

Database requirement

Django requires a database to function. When generating a new project, the default is to make use of SQLite. Using SQLite is not recommended for production, especially on Kubernetes deployments, because the database is not shared across units and any contents will be removed upon a new container being deployed. The django-framework extension therefore requires a database integration for every application, such as PostgreSQL or MySQL. See the how-to guide for how to deploy a database and integrate the Django application with it.

config.options key

You can use the predefined options (run charmcraft expand-extensions for details) but also add your own, as needed.

In the latter case, any option you define will be used to generate environment variables; a user-defined option config-option-name will generate an environment variable named DJANGO_CONFIG_OPTION_NAME where the option name is converted to upper case, dashes will be converted to underscores and the DJANGO_ prefix will be added.

In either case, you will be able to set it in the usual way by running juju config <application> <option>=<value>. For example, if you define an option called token, as below, this will generate a DJANGO_TOKEN environment variable, and a user of your charm can set it by running juju config <application> token=<token>.

config:
  options:
    token:
      description: The token for the service.
      type: string

For the predefined configuration option django-allowed-hosts, that will set the DJANGO_ALLOWED_HOSTS environment variable, the ingress URL or the Kubernetes service URL if there is no ingress integration, will be set automatically.

In addition to this, you can set the configuration option to be mandatory by setting the optional key to false. This will block the charm and stop services until the configuration is supplied. For example, if your application needs an api-token to function correctly you can set optional, as shown below. This will block the charm and stop the services until the api-token configuration is supplied.

charmcraft.yaml
config:
  options:
    api-token:
      description: The token necessary for the service to run.
      type: string
      optional: false

Note

A configuration with optional: false can’t also have a default key. If it has both, the charm will fail to pack.

Relations

Your charm already has the following peers, provides, and requires relations, as they were automatically supplied by the Django extension:

peers:
  secret-storage:
    interface: secret-storage
provides:
  metrics-endpoint:
    interface: prometheus_scrape
  grafana-dashboard:
    interface: grafana_dashboard
requires:
  logging:
    interface: loki_push_api
  ingress:
    interface: ingress
    limit: 1

In addition to these relations, in each provides and requires block you may specify further relations, to integrate with the following charms:

Relation

Endpoint definition

Ingress traefik and nginx ingress integrator

Already available in the charm

MySQL machine and Kubernetes charm

requires:
  mysql:
    interface: mysql_client
    optional: True
    limit: 1

PostgreSQL machine and Kubernetes charm

requires:
  postgresql:
    interface: postgresql_client
    optional: True
    limit: 1

MongoDB charm

requires:
  mongodb:
    interface: mongodb_client
    optional: True
    limit: 1

Canonical Observability Stack (COS)

Already available in the charm

Redis charm

requires:
  redis:
    interface: redis
    optional: True
    limit: 1

SAML charm

requires:
  saml:
    interface: saml
    optional: True
    limit: 1

S3 charm

requires:
  s3:
    interface: s3
    optional: True
    limit: 1

RabbitMQ machine and Kubernetes charm

requires:
  rabbitmq:
    interface: rabbitmq
    optional: True
    limit: 1

Tempo charm

requires:
  tracing:
    interface: tracing
    optional: True
    limit: 1

SMTP charm

requires:
  smtp:
    interface: smtp
    optional: True
    limit: 1

OpenFGA charm

requires:
  openfga:
    interface: openfga
    optional: True
    limit: 1

Note

The key optional with value False means that the charm will get blocked and stop the services if the integration is not provided.

To add one of these relations, e.g., PostgreSQL, in the project file, include the appropriate requires block and integrate with juju integrate <django charm> postgresql as usual.

Environment variables

Each relation adds its own environment variables to your Django app. Some are required, meaning they must be set for the relation to function.

The environment variable DJANGO_BASE_URL provides the Ingress URL for an Ingress relation or the Kubernetes service URL if there is no Ingress relation.

Relation

Environment variables

PostgreSQL

  • POSTGRESQL_DB_CONNECT_STRING

  • POSTGRESQL_DB_SCHEME

  • POSTGRESQL_DB_NETLOC

  • POSTGRESQL_DB_PATH

  • POSTGRESQL_DB_PARAMS

  • POSTGRESQL_DB_QUERY

  • POSTGRESQL_DB_FRAGMENT

  • POSTGRESQL_DB_USERNAME

  • POSTGRESQL_DB_PASSWORD

  • POSTGRESQL_DB_HOSTNAME

  • POSTGRESQL_DB_PORT

  • POSTGRESQL_DB_NAME

MySQL

  • MYSQL_DB_CONNECT_STRING

  • MYSQL_DB_SCHEME

  • MYSQL_DB_NETLOC

  • MYSQL_DB_PATH

  • MYSQL_DB_PARAMS

  • MYSQL_DB_QUERY

  • MYSQL_DB_FRAGMENT

  • MYSQL_DB_USERNAME

  • MYSQL_DB_PASSWORD

  • MYSQL_DB_HOSTNAME

  • MYSQL_DB_PORT

  • MYSQL_DB_NAME

MongoDB

  • MONGODB_DB_CONNECT_STRING

  • MONGODB_DB_SCHEME

  • MONGODB_DB_NETLOC

  • MONGODB_DB_PATH

  • MONGODB_DB_PARAMS

  • MONGODB_DB_QUERY

  • MONGODB_DB_FRAGMENT

  • MONGODB_DB_USERNAME

  • MONGODB_DB_PASSWORD

  • MONGODB_DB_HOSTNAME

  • MONGODB_DB_PORT

  • MONGODB_DB_NAME

Redis

  • REDIS_DB_CONNECT_STRING

  • REDIS_DB_SCHEME

  • REDIS_DB_NETLOC

  • REDIS_DB_PATH

  • REDIS_DB_PARAMS

  • REDIS_DB_QUERY

  • REDIS_DB_FRAGMENT

  • REDIS_DB_USERNAME

  • REDIS_DB_PASSWORD

  • REDIS_DB_HOSTNAME

  • REDIS_DB_PORT

  • REDIS_DB_NAME

SAML

  • SAML_ENTITY_ID (required)

  • SAML_METADATA_URL (required)

  • SAML_SINGLE_SIGN_ON_REDIRECT_URL (required)

  • SAML_SIGNING_CERTIFICATE (required)

S3

  • S3_ACCESS_KEY (required)

  • S3_SECRET_KEY (required)

  • S3_BUCKET (required)

  • S3_REGION

  • S3_STORAGE_CLASS

  • S3_ENDPOINT

  • S3_PATH

  • S3_API_VERSION

  • S3_URI_STYLE

  • S3_ADDRESSING_STYLE

  • S3_ATTRIBUTES

  • S3_TLS_CA_CHAIN

RabbitMQ

  • RABBITMQ_CONNECT_STRING

  • RABBITMQ_SCHEME

  • RABBITMQ_NETLOC

  • RABBITMQ_PATH

  • RABBITMQ_PARAMS

  • RABBITMQ_QUERY

  • RABBITMQ_FRAGMENT

  • RABBITMQ_USERNAME

  • RABBITMQ_PASSWORD

  • RABBITMQ_HOSTNAME

  • RABBITMQ_PORT

  • RABBITMQ_VHOST

Tracing

  • OTEL_EXPORTER_OTLP_ENDPOINT

  • OTEL_SERVICE_NAME

SMTP

  • SMTP_HOST

  • SMTP_PORT

  • SMTP_USER

  • SMTP_PASSWORD_ID

  • SMTP_AUTH_TYPE

  • SMTP_TRANSPORT_SECURITY

  • SMTP_DOMAIN

OpenFGA

  • FGA_STORE_ID

  • FGA_TOKEN

  • FGA_GRPC_API_URL

  • FGA_HTTP_API_URL

HTTP Proxy

Proxy settings should be set as model configurations. Charms generated using the django-framework extension will make the Juju proxy settings available as the HTTP_PROXY, HTTPS_PROXY and NO_PROXY environment variables. For example, the juju-http-proxy environment variable will be exposed as HTTP_PROXY to the Django service.

Background Tasks

Extra services defined in the file rockcraft.yaml with names ending in -worker or -scheduler will be passed the same environment variables as the main application. If there is more than one unit in the application, the services with the name ending in -worker will run in all units. The services with name ending in -scheduler will only run in one of the units of the application.

Observability

12-factor app charms are designed to be easily observable using the Canonical Observability Stack.

You can easily integrate your charm with Loki, Prometheus and Grafana using Juju.

juju integrate django-k8s grafana
juju integrate django-k8s loki
juju integrate django-k8s prometheus

After integration, you will be able to observe your workload using Grafana dashboards.

In addition to that you can also trace your workload code using Tempo.

See Charmed Tempo HA on Discourse to learn more about how to deploy Tempo.

OpenTelemetry will automatically read the environment variables and configure the OpenTelemetry SDK to use them. See the OpenTelemetry documentation for further information about tracing.

Secrets

Juju secrets can be passed as environment variables to your Django application. The secret ID has to be passed to the application as a config option in the project file of type secret. This config option has to be populated with the secret ID, in the format secret:<secret ID>.

The environment variable name passed to the application will be:

DJANGO_<config option name>_<key inside the secret>

The <config option name> and <key inside the secret> keywords in the environment variable name will have the hyphens replaced by underscores and all the letters capitalised.

See more: Juju | Secret

Grafana dashboard graphs

If the Django app is connected to the Canonical Observability Stack (COS), the Grafana dashboard Django Operator displays the following default graphs:

  • Requests: Number of requests over time.

  • Status code count: Number of requests broken by responses status code.

  • Requests per second: Number of requests per second over time.

  • 2XX Rate: Portion of responses that were successful (in the 200 range).

  • 3XX Rate: Portion of responses that were redirects (in the 300 range).

  • 4XX Rate: Portion of responses that were client errors (in the 400 range).

  • 5XX Rate: Portion of responses that were server errors (in the 500 range).

  • Request average duration: Average duration of the requests over time.

  • Request duration percentile: The 50th, 90th, and 99th percentile of all the request duration lengths after sorting them from slowest to fastest. For example, the 50th percentile represents the length of time (or less) that 50% of the requests lasted.