fanout / django-eventstream

Server-Sent Events for Django
MIT License
638 stars 84 forks source link

django 2.2 implement alongside websockets and i get a AttributeError: module 'django_eventstream.urls' has no attribute 'callback' #106

Open simkimsia opened 1 year ago

simkimsia commented 1 year ago

this is my asgi.py

"""
ASGI entrypoint. Configures Django and then runs the application
defined in the ASGI_APPLICATION setting.
"""
import os

import django
from channels.routing import get_default_application
from django.conf import settings

# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
# if running multiple sites in the same mod_wsgi process. To fix this, use
# mod_wsgi daemon mode with each site in its own daemon process, or use
# os.environ["DJANGO_SETTINGS_MODULE"] = "config.settings.production"
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")

if not settings.configured:
    # set the default Django settings module for the 'celery' program.
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.local')  # pragma: no cover

django.setup()
application = get_default_application()

this is my routing.py

import django_eventstream
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import path

from websockets.consumers import WSConsumer

application = ProtocolTypeRouter({
    "websocket": AuthMiddlewareStack(
        URLRouter([
            path("websocket/", WSConsumer),
        ])
    ),
    'http': URLRouter([
        path('events/', AuthMiddlewareStack(
            URLRouter(django_eventstream.routing.urlpatterns)
        ), { 'channels': ['test'] }),
        path('pre_quotations_bulk_create_requests/(?P<pk>\d+)/events/$',
            include(django_eventstream.urls),
            {'format-channels': ['pre_quotations_bulk_create_request-{pk}']}),
    ]),
})

my requirements

celery[redis]==5.2.7 # May 2022 https://github.com/celery/celery
channels==3.0.5  # June 2022 channels 3 work with eventstream and django 2.2 https://github.com/django/channels/releases/tag/3.0.5
channels-redis==3.4.1  # Jul 2022 https://github.com/django/channels_redis/releases/tag/3.4.1
django-eventstream==4.5.0 # Dec 2022 https://github.com/fanout/django-eventstream/releases/tag/4.5.0

What is my objective?

i want to use SSE for

/pre_quotations_bulk_create_requests/(?P<pk>\d+)/events/

What's the issue?

i cannot use include as per the code snippet at https://github.com/fanout/django-eventstream#routes-and-channel-selection

# specify a list of dynamic channels using formatting based on view keywords
path('objects/<obj_id>/events/', include(django_eventstream.urls),
    {'format-channels': ['object-{obj_id}']})

i get a

 File "/app/websockets/routing.py", line 14, in <module>
eno-a3-django-django-1     |     'http': URLRouter([
eno-a3-django-django-1     |   File "/opt/venv/lib/python3.10/site-packages/channels/routing.py", line 129, in __init__
eno-a3-django-django-1     |     raise ImproperlyConfigured(
eno-a3-django-django-1     | django.core.exceptions.ImproperlyConfigured: <URLResolver <module 'django_eventstream.urls' from '/opt/venv/lib/python3.10/site-packages/django_eventstream/urls.py'> (None:None) 'pre_quotations_bulk_create_requests/(?P<pk>\d+)/events/$'>: include() is not supported in URLRouter. Use nested URLRouter instances instead.

so i change to

        path('pre_quotations_bulk_create_requests/(?P<pk>\d+)/events/$',
            URLRouter([django_eventstream.urls])
            {'format-channels': ['pre_quotations_bulk_create_request-{pk}']}),

now i get a

eno-a3-django-django-1     |   File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
eno-a3-django-django-1     |   File "<frozen importlib._bootstrap_external>", line 883, in exec_module
eno-a3-django-django-1     |   File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
eno-a3-django-django-1     |   File "/app/websockets/routing.py", line 19, in <module>
eno-a3-django-django-1     |     URLRouter([django_eventstream.urls]),
eno-a3-django-django-1     |   File "/opt/venv/lib/python3.10/site-packages/channels/routing.py", line 125, in __init__
eno-a3-django-django-1     |     if getattr(route.callback, "_path_routing", False) is True:
eno-a3-django-django-1     | AttributeError: module 'django_eventstream.urls' has no attribute 'callback'
eno-a3-django-mailhog-1    | [APIv1] KEEPALIVE /api/v1/events

What do I do now?

jowenn commented 1 year ago

Not tested, but guessing from the documentation is should be:

path('pre_quotations_bulk_create_requests/(?P\d+)/events/$', URLRouter(django_eventstream.urls.urlpatterns), {'format-channels': ['pre_quotations_bulk_create_request-{pk}']}),

django_eventstream.urls.urlpatterns is a list of Pathes, and that's what URLRouter expects

jkarneges commented 1 year ago

Ah, I just realized the examples in the routes section use the style expected by urls.py which only works in WSGI mode.

The examples need to be slightly adjusted for use with ASGI. Namely, the second argument to the path should be URLRouter(django_eventstream.routing.urlpatterns), and that value needs to be wrapped in AuthMiddlewareStack if you want to handle auth.