Что нового появилось в Django Channels?

С момента последнего поста про Django Channels прошло много времени, проект развивается и потихоньку идёт к стабильному релизу. В новых версиях пакета появляются интересные фишки о которых я сегодня расскажу вкратце:

Generic Consumers

Generic Consumers чем то напоминают Class Based Views в Django. Их задача сократить количество кода при написании обработчиков каналов, а также улучшить их структуру и внешний вид.

Базовым классом является BaseConsumer.

from channels.generic import BaseConsumer
class MyConsumer(BaseConsumer):
    method_mapping = {
        "your.channel.name": "method_name",
    }
    def method_name(self, message, **kwargs):
        pass

У класса есть атрибут-словарь method_mapping, где ключом является наименование канала, а значением - функция, обрабатывающая данный канал. В случае использования т.н. Class Based Consumers, в настройках роутов нужно прописывать:

from channels import route, route_class
channel_routing = [
    route_class(consumers.MyConsumer, path=r"^/myconsumer/"),
]

То есть нужно использовать метод route_class. В последней на данный момент версии (0.17.2), у классов появился метод .as_route()

В пакете также появился WebsocketConsumer, определяющий каркас для работы с WebSocket.

from channels.generic.websockets import WebsocketConsumer
class MyWebsocketConsumer(WebsocketConsumer):
    def connection_groups(self, **kwargs):
        """
        Возвращает список групп для подключения/удаления подключенных участников
        """
        return ['general_group']
    def connect(self, message, **kwargs):
        """
        Срабатывает при старте соединения по WebSocket
        """
        pass
    def receive(self, text=None, bytes=None, **kwargs):
        """
        Срабатывает, когда приходит сообщение в WebSocket
        """
        # Echo
        self.send(text=text, bytes=bytes)
    def disconnect(self, message, **kwargs):
        """
        Срабатывает при разрыве соединения
        """
        pass

Если в момент соединения есть необходимость добавлять участника в группу/группы, то переопределите метод connection_groups, и укажите список групп. При разрыве соединения участники будут автоматически удалятся из заданных групп.

Data binding

API data binding ещё до конца не устаканился и поэтому до стабильного релиза может изменяться. Используйте этот функционал аккуратно, и внимательно читайте Changelog при обновлениях django-channels. Главная задача data binding упростить жизнь при обновлениях в моделях Django. Функциональная часть построена на родных Django Signals и имеет ряд ограничений:

  • Если вы изменяете объект модели за пределами Django или используете метод .update() на объекте QuerySet, binding не сработает, так как сигнала не произойдёт.
  • В качестве сериализаторов моделей используются стандартные средства Django, но при SPA (Single Page Applications) очень часто требуется гибкость в передаваемых данных. Автор советует в таком случае использовать пакет сериализаторов из Django REST Framework.

Подробно с деталями можно почитать тут.

Роутинг с фильтрами

Веб-сокет, например, можно открыть по конкретному URL:

route("websocket.connect", consumers.ws_connect, path=r"^/chat/$")

Нужно фильтровать по входным данным для функции-consumer? Не проблема:

route("email.receive", comment_response, to_address=r".*@example.com$", subject="^reply")

Все именованные аргументы передаются в функцию-consumer, поэтому ловите их там через **kwargs.

Подробнее тут.