Skip to content

New WebSocket Endpoint

In this tutorial we create a new websocket endpoint.

Model

First we have to create a model. In this example a simple patient model.

from django.db import models

class Patient(models.Model):
    """
    Patient instance.
    """
    first_name = models.CharField(max_length=240)
    last_name = models.CharField(max_length=240)
    admission_date = models.DateTimeField()
    dismissal_date = models.DateTimeField(blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
file: dashboard/patients/models.py

Serializer

The second step is to serialize the model. To do so, we import the serializer from the Django Rest Framework and create a new Serializer Class, that inherits from the ModelSerializer. The base model for this serializer is the just created patient model. In the fields argument we may list all the fields we want to serialize. It is also possible to define __all__ or exclude certain fields.

from rest_framework import serializers
from dashboard.patients.models import Patient

class PatientSerializer(serializers.ModelSerializer):
    class Meta:
        model = Patient
        fields = ["id", "first_name", "last_name", "admission_date",
                  "dismissal_date", "updated_at", "created_at"]

file: dashboard/patients/api/serializers.py

Consumer

To be able to make the serialized data available to connected clients, a consumer needs to be set up. Clients that are connected to the WebSocket are called consumers. A fairly minimalistic setup looks something like this. Notice that a couple of Mixins are imported from the Django Channels Rest Framework, which provide the basic functionality. The serializer is the one we just created and the queryset is the one from the model above. To allow only authenticated users to connect, the permission_classes are set to ìsAuthenticated.

from djangochannelsrestframework import permissions
from djangochannelsrestframework.generics import GenericAsyncAPIConsumer
from djangochannelsrestframework.mixins import (
    ListModelMixin,
    RetrieveModelMixin,
    UpdateModelMixin,
    PatchModelMixin,
    DeleteModelMixin,
    CreateModelMixin,
)

from dashboard.patients.api.serializers import PatientSerializer
from dashboard.patients.models import Patient


class PatientConsumer(ListModelMixin, RetrieveModelMixin, PatchModelMixin, UpdateModelMixin,
                      CreateModelMixin,
                      DeleteModelMixin, GenericAsyncAPIConsumer):
    queryset = Patient.objects.all()
    serializer_class = PatientSerializer
    permission_classes = (permissions.IsAuthenticated,)

file: dashboard/patients/consumers.py

Info

The Mixins that the consumer inherits from, are the actions that the WebSocket will provide. In the listing above you can e.g. see a ListModelMixin which will provide the list action for the consumer.

URLs

Finally, we have to define a route for the WebSocket, just like with the REST API. The routes for the WebSockets are called streams and are defined in asgi.py. In this file you will find the ProtocolTypeRouter, that routes HTTP and WebSocket requests accordingly. Here, the starting point for the WebSocket is defined as /ws, whereas we defined the starting point for REST API endpoints as /api (not here). The stream we define here will be the string that follows the /ws/. So in this case, our new route, that is connected to the PatientConsumer that we created in the previous step will be called patients. Notice, that within this definition, the patients is not declared with quotation marks. However, the resulting route/URL is www.example.com/ws/patients/. But with an important change to the REST API endpoints, because instead of:

http://www.example.com/api/patients/ or https://www.example.com/api/patients/

we now have a change in protocols and must use:

ws://ww.example.com/ws/patients/ or wss://ww.example.com/ws/patients/

from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application
from django.urls import re_path

from dashboard.patients.consumers import PatientConsumer
from channelsmultiplexer import AsyncJsonWebsocketDemultiplexer
from config.middleware import TokenAuthMiddlewareStack


application = ProtocolTypeRouter({
    "http": get_asgi_application(),
    "websocket": TokenAuthMiddlewareStack(
        URLRouter(
            [re_path(r"^ws/$", AsyncJsonWebsocketDemultiplexer(
                patients=PatientConsumer().as_asgi(),
            ).as_asgi()), ]
        )
    ),
})

file: config/asgi.py