Synchronous views limit concurrency. Django 3.0 introduces ASGI, enabling async views and WebSocket support. At ZIRA Software, Django 3.0 powers real-time healthcare applications requiring concurrent connections.
ASGI vs WSGI
WSGI (Web Server Gateway Interface):
- Synchronous only
- One request per thread/process
- Blocking I/O
- Standard since Django 1.0
ASGI (Asynchronous Server Gateway Interface):
- Async and sync support
- Multiple concurrent connections
- Non-blocking I/O
- WebSocket support
Installation and Setup
Requirements:
pip install django==3.0
pip install channels # For ASGI support
Create ASGI application:
# myproject/asgi.py
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myproject.settings')
application = get_asgi_application()
Run with ASGI server:
# Development
python manage.py runserver
# Production (with Daphne)
pip install daphne
daphne -b 0.0.0.0 -p 8000 myproject.asgi:application
# Production (with Uvicorn)
pip install uvicorn
uvicorn myproject.asgi:application --host 0.0.0.0 --port 8000
Async Views
Async function-based views:
# views.py
import asyncio
import httpx
from django.http import JsonResponse
async def async_view(request):
# Async HTTP client
async with httpx.AsyncClient() as client:
response = await client.get('https://api.example.com/data')
data = response.json()
return JsonResponse({'data': data})
Multiple async operations:
import asyncio
async def dashboard(request):
# Run multiple async operations concurrently
user_data, orders, notifications = await asyncio.gather(
fetch_user_data(request.user.id),
fetch_recent_orders(request.user.id),
fetch_notifications(request.user.id),
)
return JsonResponse({
'user': user_data,
'orders': orders,
'notifications': notifications,
})
async def fetch_user_data(user_id):
# Simulate async database call
await asyncio.sleep(0.1)
return {'id': user_id, 'name': 'John Doe'}
async def fetch_recent_orders(user_id):
await asyncio.sleep(0.1)
return [{'id': 1, 'total': 99.99}]
async def fetch_notifications(user_id):
await asyncio.sleep(0.1)
return [{'message': 'New order received'}]
Async class-based views:
from django.views import View
from django.http import JsonResponse
class AsyncApiView(View):
async def get(self, request):
data = await self.fetch_data()
return JsonResponse({'data': data})
async def post(self, request):
result = await self.process_data(request.POST)
return JsonResponse({'result': result})
async def fetch_data(self):
await asyncio.sleep(0.1)
return {'message': 'Data fetched'}
async def process_data(self, data):
await asyncio.sleep(0.1)
return {'processed': True}
Async Database Queries
Note: Django 3.0 ORM is still synchronous. Use sync_to_async wrapper:
from django.contrib.auth.models import User
from asgiref.sync import sync_to_async
async def get_user_async(user_id):
# Wrap synchronous ORM call
user = await sync_to_async(User.objects.get)(id=user_id)
return user
async def user_detail(request, user_id):
user = await get_user_async(user_id)
return JsonResponse({
'id': user.id,
'username': user.username,
'email': user.email,
})
Query multiple objects:
@sync_to_async
def get_users():
return list(User.objects.filter(is_active=True)[:10])
async def users_list(request):
users = await get_users()
return JsonResponse({
'users': [{'id': u.id, 'username': u.username} for u in users]
})
WebSocket Support with Channels
Install Django Channels:
pip install channels
Configure:
# settings.py
INSTALLED_APPS = [
'channels',
# ...
]
ASGI_APPLICATION = 'myproject.asgi.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
'hosts': [('127.0.0.1', 6379)],
},
},
}
WebSocket consumer:
# consumers.py
import json
from channels.generic.websocket import AsyncWebsocketConsumer
class ChatConsumer(AsyncWebsocketConsumer):
async def connect(self):
self.room_name = self.scope['url_route']['kwargs']['room_name']
self.room_group_name = f'chat_{self.room_name}'
# Join room group
await self.channel_layer.group_add(
self.room_group_name,
self.channel_name
)
await self.accept()
async def disconnect(self, close_code):
# Leave room group
await self.channel_layer.group_discard(
self.room_group_name,
self.channel_name
)
async def receive(self, text_data):
data = json.loads(text_data)
message = data['message']
# Send message to room group
await self.channel_layer.group_send(
self.room_group_name,
{
'type': 'chat_message',
'message': message
}
)
async def chat_message(self, event):
message = event['message']
# Send message to WebSocket
await self.send(text_data=json.dumps({
'message': message
}))
Routing:
# routing.py
from django.urls import path
from . import consumers
websocket_urlpatterns = [
path('ws/chat/<str:room_name>/', consumers.ChatConsumer.as_asgi()),
]
# asgi.py
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
import myapp.routing
application = ProtocolTypeRouter({
'http': get_asgi_application(),
'websocket': AuthMiddlewareStack(
URLRouter(
myapp.routing.websocket_urlpatterns
)
),
})
MariaDB Support
New in Django 3.0:
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mydatabase',
'USER': 'myuser',
'PASSWORD': 'mypassword',
'HOST': 'localhost',
'PORT': '3306',
'OPTIONS': {
'charset': 'utf8mb4',
},
}
}
MariaDB-specific features:
- JSON field support
- Check constraints
- Improved performance
Exclusion Constraints (PostgreSQL)
from django.contrib.postgres.constraints import ExclusionConstraint
from django.contrib.postgres.fields import DateTimeRangeField, RangeOperators
from django.db import models
class Booking(models.Model):
room = models.ForeignKey(Room, on_delete=models.CASCADE)
during = DateTimeRangeField()
class Meta:
constraints = [
ExclusionConstraint(
name='exclude_overlapping_bookings',
expressions=[
('during', RangeOperators.OVERLAPS),
('room', RangeOperators.EQUAL),
],
),
]
Python 3.6+ Features
F-strings in queries:
# Django 3.0 requires Python 3.6+
name = 'John'
users = User.objects.filter(username__icontains=name)
Dataclasses support:
from dataclasses import dataclass
@dataclass
class UserDTO:
id: int
username: str
email: str
def get_user_dto(user_id):
user = User.objects.get(id=user_id)
return UserDTO(
id=user.id,
username=user.username,
email=user.email
)
Migration to ASGI
1. Update project:
pip install django==3.0
python manage.py migrate
2. Test async views:
# Test async view
async def test_view(request):
await asyncio.sleep(0.1)
return JsonResponse({'status': 'ok'})
3. Deploy with ASGI server:
# Using Daphne
daphne myproject.asgi:application
# Using Uvicorn
uvicorn myproject.asgi:application
Performance Considerations
When to use async:
- I/O-bound operations (API calls, file operations)
- WebSocket connections
- Long-polling
- Server-sent events
When NOT to use async:
- CPU-bound operations
- Simple CRUD views
- ORM-heavy operations (still synchronous)
Conclusion
Django 3.0 modernizes with ASGI support, enabling async views and WebSockets. MariaDB support and Python 3.6+ requirements prepare Django for the future.
Building real-time Django applications? Contact ZIRA Software for Python/Django expertise.