Python Cloud Advocate at Microsoft
Formerly: UC Berkeley, Coursera, Khan Academy, Google
Find Pamela online at:
Mastodon | @pamelafox@fosstodon.org |
@pamelafox | |
GitHub | www.github.com/pamelafox |
Website | pamelafox.org |
To follow along with the exercises, your options are:
Django, an external library, is an opinionated framework for server-side code. Includes an ORM for database interaction.
Apps written in Django:
github.com/Azure-Samples/azure-django-postgres-flexible-appservice
aka.ms/django-pgflex-app
Run DB migrations:
python3 src/manage.py migrate
Load seed data:
python3 src/manage.py loaddata src/seed_data.json
Run the server:
python3 src/manage.py runserver 8000
This app follows a typical Django project structure:
src/
manage.py
project/
__init__.py
asgi.py
settings.py
urls.py
wsgi.py
relecloud/
__init__.py
admin.py
apps.py
models.py
urls.py
views.py
templates/
The relecloud
folder represents a Django "app".
We can add more "app"s to the project, each with its own models, views, urls, etc.
Models are Python classes that represent database tables.
from django.db import models
class Destination(models.Model):
name = models.CharField(unique=True, max_length=50, null=False, blank=False)
subtitle = models.CharField(unique=False, max_length=240, null=False, blank=True)
description = models.TextField(max_length=2000, null=False, blank=False)
🔗 From models.py
To create a migration:
python3 src/manage.py makemigrations
To apply the migration:
python3 src/manage.py migrate
Views can be simple Python functions:
def index(request):
return render(request, "index.html")
Or subclasses of Django's generic views:
class CruiseDetailView(generic.DetailView):
template_name = "cruise_detail.html"
model = models.Cruise
🔗 From views.py
Templates are HTML files written in Django template language (Jinja2-like):
<p>This cruise visits the following destinations:</p>
{% for destination in cruise.destinations.all %}
<a class="list-group-item list-group-item-action" href="{% url 'destination_detail' destination.id %}">{{ destination }}</a>
{% endfor %}
URLs map paths to views:
urlpatterns = [
path("", views.index, name="index"),
path("about", views.about, name="about"),
path("destinations/", views.destinations, name="destinations"),
path(
"destination/<int:pk>",
views.DestinationDetailView.as_view(),
name="destination_detail",
),
path("cruise/<int:pk>", views.CruiseDetailView.as_view(), name="cruise_detail"),
path("info_request", views.InfoRequestCreate.as_view(), name="info_request"),
]
🔗 From urls.py
Django includes a built-in admin interface for managing data.
admin.site.register(models.Cruise)
admin.site.register(models.Destination)
admin.site.register(models.InfoRequest)
🔗 From admin.py
To log in to the admin interface:
python3 src/manage.py createsuperuser
Using this repo:
github.com/Azure-Samples/azure-django-postgres-flexible-appservice
aka.ms/django-pgflex-app
.vscode/launch.json:
{
"version": "0.2.0",
"configurations": [{
"name": "Python: Django",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/src/manage.py",
"args": [
"runserver"
],
"django": true,
"justMyCode": true
}]}
In settings.py:
DEBUG_PROPAGATE_EXCEPTIONS = env("DEBUG") # True locally
Add to .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [{
"name": "Python: Django",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/src/manage.py",
"args": [
"runserver"
],
"django": true,
"justMyCode": true,
"jinja": true // Add this line
}]}
Django is designed to be extensible. Some popular extensions:
🔗 Read more: 20 Django Packages I Use in Every Project
The Django REST framework can be used to create CRUD APIs:
from django.urls import path, include
from django.contrib.auth.models import User
from rest_framework import routers, serializers, viewsets
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ['url', 'username', 'email', 'is_staff']
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
router = routers.DefaultRouter()
router.register(r'users', UserViewSet)
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
Wagtail is a popular CMS built on Django.
✨ Now with AI!
Wagtail AI adds AI-based helpers to form fields.
Wagtail Vector Index adds vector search to Wagtail.
Check out Paolo's talk on Django and Vector Search:
https://www.citusdata.com/posette/2024/schedule/#livestream4
Vue frontend plus Django-REST + Wagtail backend:
Using the built-in Django server:
python3 -m src/manage.py runserver 8000
⚠️ But the dev server is not recommended for production use.
Gunicorn is a production-level server that can run multiple worker processes.
Add gunicorn
to requirements.txt
:
gunicorn==22.0.0
Use gunicorn
to run Django app with multiple workers:
python3 -m gunicorn project.wsgi --workers 4 --bind 0.0.0.0:8555
Gunicorn can be configured with a gunicorn.conf.py
file:
import multiprocessing
max_requests = 1000
max_requests_jitter = 50
log_file = "-"
bind = "0.0.0.0:8000"
workers = (multiprocessing.cpu_count() * 2) + 1
threads = workers
timeout = 600
The run command can be simplified to:
python3 -m gunicorn project.wsgi
Azure Container Apps | Azure Functions | |||
Azure Kubernetes Service | Container Management | Azure App Service | Serverless | |
Environment | Containers | PaaS | ||
Cloud | Azure |
For Django, App Service is easiest way to get started.
Considerations:
Option | Description |
---|---|
Azure Database for PostgreSQL – Flexible Server | Microsoft's most recent PostgreSQL offering. Fully managed service with vertical scaling. |
Azure Cosmos DB for PostgreSQL | Distributed database using PostgreSQL and the Citus extension. Can scale horizontally. |
Azure SQL Database | Microsoft's managed service for SQL Server. Can be used in Django via microsoft/mssql-django |
⭐️ In production, use passwordless authentication for the database:
⚠️ If you must use a password, store in Azure KeyVault.
See aka.ms/django-quiz-app
Django requires a secret key for security, defined in settings.py
:
SECRET_KEY = os.environ.get("SECRET_KEY")
For production, store this in a secure location, such as Azure Key Vault. 🔑
To fetch the secret value, use a key vault reference in environment variables:
SECRET_KEY: '@Microsoft.KeyVault(VaultName=${keyVaultName};SecretName=djangoSecretKey)'
(Also possible in Container App settings)
A few options for efficiently serving static files in production:
As shown in aka.ms/django-quiz-app.
As shown in tonybaloney/django-on-azure.
Both options could optionally be used with a CDN (Azure Front Door) in front.
One possible architecture:
Using this repo:
github.com/pamelafox/django-quiz-app
aka.ms/django-quiz-app
azd down
to un-deploy the app (so that you don't waste cloud resources unnecessarily).
Restrict network access:
Make it harder to access admin:
ADMIN_URL = os.environ.get("ADMIN_URL")
Also check out the Django tutorial.