django-actioncable


Namedjango-actioncable JSON
Version 1.0.4 PyPI version JSON
download
home_pagehttps://github.com/AccordBox/django-actioncable
SummaryThis package provides Rails Action Cable support to Django
upload_time2024-01-18 07:34:59
maintainer
docs_urlNone
authorMichael Yin
requires_python>=3.8
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # README

This package provides Rails Action Cable support to Django Channels.

## Install

Please make sure [Django channels](https://channels.readthedocs.io/) is already working in Django project before installing this package.

```bash
$ pip install django-actioncable
```

In the `asgi.py`, we have code like this

```python
import os

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

from django_app.core import routing

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_app.settings")

application = ProtocolTypeRouter(
    {
        "http": get_asgi_application(), 
        "websocket": URLRouter(routing.urlpatterns)
    }
)
```

Notes:

1. The `websocket` protocol would be handled by `URLRouter(routing.urlpatterns)`

In the routing file, we add below code:

```python
from actioncable import ActionCableConsumer


urlpatterns = [
    path("cable", ActionCableConsumer.as_asgi()),
]
```

Notes:

1. So all the Websocket requests sent to `ws://localhost:8000/cable` would be handled by `ActionCableConsumer`
2. The `ActionCableConsumer` would then dispatch the request to the corresponding channel class.

We can add below code to the routing file to register the channel class.

```python
from actioncable import ActionCableConsumer, CableChannel, cable_channel_register


@cable_channel_register
class ChatChannel(CableChannel):

    def __init__(self, consumer: ActionCableConsumer, identifier_key, params=None):
        self.params = params if params else {}
        self.identifier_key = identifier_key
        self.consumer = consumer
        self.group_name = None

    async def subscribe(self):
        self.group_name = f"chat_{self.params['pk']}"
        await self.consumer.subscribe_group(self.group_name, self)

    async def unsubscribe(self):
        await self.consumer.unsubscribe_group(self.group_name, self)
```

1. We create a `ChatChannel`, which inherits from the `CableChannel`. 
2. The `cable_channel_register` decorator would register the `ChatChannel` class to the `ActionCableConsumer`.
3. In the `subscribe` callback method, we get the room pk from the `self.params` dict and subscribe the channel to the group `chat_{pk}`. 
4. In the `unsubscribe` callback method, we unsubscribe the channel from the group.

## HTML

```html
<!DOCTYPE html>
<html>
<head>
  <title>ActionCable Example</title>
</head>
<body>
<div id="messages"></div>

<script src="https://cdn.jsdelivr.net/npm/@rails/actioncable@7.1.2/app/assets/javascripts/actioncable.js"></script>
<script>
  document.addEventListener("DOMContentLoaded", function () {
    // Create a consumer object to connect to the ActionCable server
    const cable = ActionCable.createConsumer();

    // Define a channel and its corresponding functions
    const channel = cable.subscriptions.create({channel: "ChatChannel", pk: "1"}, {
      connected() {
        console.log("Connected to the chat channel.");
      },

      disconnected() {
        console.log("Disconnected from the chat channel.");
      },

      received(data) {
        // Display the received message
        const messagesDiv = document.getElementById("messages");
        const messageDiv = document.createElement("div");
        messageDiv.innerText = data;
        messagesDiv.appendChild(messageDiv);
      }
    });
  });
</script>

</body>
</html>
```

Notes:

1. We use the `ActionCable.createConsumer()` to create a consumer object to connect to the ActionCable server.
2. The `channe` is `ChatChannel`, so the `ChatChannel` we just created will be used to handle the request.
3. In the client, we can pass room pk to the `ChatChannel` by `pk: "1"`, and in the backend we can get it in the `self.params`
4. In this case, the channel will `subscribe` to the `chat_1` group.

## Test

Launch Django shell, and run below code:

```python
from actioncable import cable_broadcast

cable_broadcast("chat_1", message="Hello World")
```

You should be able to see the message appear on the web page.

`cable_broadcast` is a wrapper of Django Channel `async_to_sync(channel_layer.group_send)` method call, we can use it in Django view or external process such as Celery worker.

The `message` value can also be Python dict, and in javascript we can get it in the `data` parameter of the `received` callback method.


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/AccordBox/django-actioncable",
    "name": "django-actioncable",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "",
    "keywords": "",
    "author": "Michael Yin",
    "author_email": "michaelyin@accordbox.com",
    "download_url": "https://files.pythonhosted.org/packages/a8/d7/e203e37e9cc574c58bb4e824897743db985038602c2acaa1ecda2512a893/django_actioncable-1.0.4.tar.gz",
    "platform": null,
    "description": "# README\n\nThis package provides Rails Action Cable support to Django Channels.\n\n## Install\n\nPlease make sure [Django channels](https://channels.readthedocs.io/) is already working in Django project before installing this package.\n\n```bash\n$ pip install django-actioncable\n```\n\nIn the `asgi.py`, we have code like this\n\n```python\nimport os\n\nfrom channels.routing import ProtocolTypeRouter, URLRouter\nfrom django.core.asgi import get_asgi_application\n\nfrom django_app.core import routing\n\nos.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"django_app.settings\")\n\napplication = ProtocolTypeRouter(\n    {\n        \"http\": get_asgi_application(), \n        \"websocket\": URLRouter(routing.urlpatterns)\n    }\n)\n```\n\nNotes:\n\n1. The `websocket` protocol would be handled by `URLRouter(routing.urlpatterns)`\n\nIn the routing file, we add below code:\n\n```python\nfrom actioncable import ActionCableConsumer\n\n\nurlpatterns = [\n    path(\"cable\", ActionCableConsumer.as_asgi()),\n]\n```\n\nNotes:\n\n1. So all the Websocket requests sent to `ws://localhost:8000/cable` would be handled by `ActionCableConsumer`\n2. The `ActionCableConsumer` would then dispatch the request to the corresponding channel class.\n\nWe can add below code to the routing file to register the channel class.\n\n```python\nfrom actioncable import ActionCableConsumer, CableChannel, cable_channel_register\n\n\n@cable_channel_register\nclass ChatChannel(CableChannel):\n\n    def __init__(self, consumer: ActionCableConsumer, identifier_key, params=None):\n        self.params = params if params else {}\n        self.identifier_key = identifier_key\n        self.consumer = consumer\n        self.group_name = None\n\n    async def subscribe(self):\n        self.group_name = f\"chat_{self.params['pk']}\"\n        await self.consumer.subscribe_group(self.group_name, self)\n\n    async def unsubscribe(self):\n        await self.consumer.unsubscribe_group(self.group_name, self)\n```\n\n1. We create a `ChatChannel`, which inherits from the `CableChannel`. \n2. The `cable_channel_register` decorator would register the `ChatChannel` class to the `ActionCableConsumer`.\n3. In the `subscribe` callback method, we get the room pk from the `self.params` dict and subscribe the channel to the group `chat_{pk}`. \n4. In the `unsubscribe` callback method, we unsubscribe the channel from the group.\n\n## HTML\n\n```html\n<!DOCTYPE html>\n<html>\n<head>\n  <title>ActionCable Example</title>\n</head>\n<body>\n<div id=\"messages\"></div>\n\n<script src=\"https://cdn.jsdelivr.net/npm/@rails/actioncable@7.1.2/app/assets/javascripts/actioncable.js\"></script>\n<script>\n  document.addEventListener(\"DOMContentLoaded\", function () {\n    // Create a consumer object to connect to the ActionCable server\n    const cable = ActionCable.createConsumer();\n\n    // Define a channel and its corresponding functions\n    const channel = cable.subscriptions.create({channel: \"ChatChannel\", pk: \"1\"}, {\n      connected() {\n        console.log(\"Connected to the chat channel.\");\n      },\n\n      disconnected() {\n        console.log(\"Disconnected from the chat channel.\");\n      },\n\n      received(data) {\n        // Display the received message\n        const messagesDiv = document.getElementById(\"messages\");\n        const messageDiv = document.createElement(\"div\");\n        messageDiv.innerText = data;\n        messagesDiv.appendChild(messageDiv);\n      }\n    });\n  });\n</script>\n\n</body>\n</html>\n```\n\nNotes:\n\n1. We use the `ActionCable.createConsumer()` to create a consumer object to connect to the ActionCable server.\n2. The `channe` is `ChatChannel`, so the `ChatChannel` we just created will be used to handle the request.\n3. In the client, we can pass room pk to the `ChatChannel` by `pk: \"1\"`, and in the backend we can get it in the `self.params`\n4. In this case, the channel will `subscribe` to the `chat_1` group.\n\n## Test\n\nLaunch Django shell, and run below code:\n\n```python\nfrom actioncable import cable_broadcast\n\ncable_broadcast(\"chat_1\", message=\"Hello World\")\n```\n\nYou should be able to see the message appear on the web page.\n\n`cable_broadcast` is a wrapper of Django Channel `async_to_sync(channel_layer.group_send)` method call, we can use it in Django view or external process such as Celery worker.\n\nThe `message` value can also be Python dict, and in javascript we can get it in the `data` parameter of the `received` callback method.\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "This package provides Rails Action Cable support to Django",
    "version": "1.0.4",
    "project_urls": {
        "Changelog": "https://github.com/AccordBox/django-actioncable/releases",
        "Homepage": "https://github.com/AccordBox/django-actioncable"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "63b872af5276ea41e4c60cc785e878f121b36a07c3658867c81ae7294dec53b3",
                "md5": "b48b5233cfaa6736c7cad3fd19f4141c",
                "sha256": "c7becceb29a6748266a8b35b426103506549d4d759c031ef0468a09f61161524"
            },
            "downloads": -1,
            "filename": "django_actioncable-1.0.4-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "b48b5233cfaa6736c7cad3fd19f4141c",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 5655,
            "upload_time": "2024-01-18T07:34:57",
            "upload_time_iso_8601": "2024-01-18T07:34:57.868373Z",
            "url": "https://files.pythonhosted.org/packages/63/b8/72af5276ea41e4c60cc785e878f121b36a07c3658867c81ae7294dec53b3/django_actioncable-1.0.4-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a8d7e203e37e9cc574c58bb4e824897743db985038602c2acaa1ecda2512a893",
                "md5": "70c17b8234fc78a9efce33bb0486e927",
                "sha256": "0b24111b27e7aa6ed3cad1acaca47b3537dc73d49c266c5c4b2b42b079c2d6bb"
            },
            "downloads": -1,
            "filename": "django_actioncable-1.0.4.tar.gz",
            "has_sig": false,
            "md5_digest": "70c17b8234fc78a9efce33bb0486e927",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 4497,
            "upload_time": "2024-01-18T07:34:59",
            "upload_time_iso_8601": "2024-01-18T07:34:59.040963Z",
            "url": "https://files.pythonhosted.org/packages/a8/d7/e203e37e9cc574c58bb4e824897743db985038602c2acaa1ecda2512a893/django_actioncable-1.0.4.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-01-18 07:34:59",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "AccordBox",
    "github_project": "django-actioncable",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "django-actioncable"
}
        
Elapsed time: 4.43014s