0

I use the API https://rapidapi.com/chicmi/api/chicmi-local-fashion/ and websockets in Django. I have an HTML form where I enter the number of days and maximum result, click a button, and nothing happens. When trying to open the page http://127.0.0.1:8000/events/London/, the browser also attempts to establish a WebSocket connection using the URL ws://127.0.0.1:8000/ws/London/, but the server cannot find a corresponding handler for this URL and returns a 404 error. So, I need to redirect the client to a page with fashion show data after the client enters data into the form. Please advise on how to fix the error.

[11/May/2023 20:55:04] "GET /events/London/ HTTP/1.1" 200 1676 Not Found: /ws/London/ [11/May/2023 20:55:04] "GET /ws/London/ HTTP/1.1" 404 4822

I tried to configure the paths correctly, but I still get an error

[11/May/2023 20:55:04] "GET /events/London/ HTTP/1.1" 200 1676 Not Found: /ws/London/ [11/May/2023 20:55:04] "GET /ws/London/ HTTP/1.1" 404 4822

My code

events.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Events</title>
    <script>
        var ws_url = 'ws://' + window.location.host + '/ws/' + '{{ city }}' + '/';
        var ws = new WebSocket(ws_url);
        ws.onmessage = function(event) {
            var event_data = JSON.parse(event.data)['event_data'];
            var event_list = document.getElementById('event-list');
            event_list.innerHTML = '';
            for (var i = 0; i < event_data.length; i++) {
                var event = event_data[i];
                var event_element = document.createElement('div');
                event_element.innerHTML = '<h2>' + event['event_name'] + '</h2>' +
                                          '<img src="' + event['event_preview_url'] + '">' +
                                          '<p><a href="' + event['detail_url'] + '">More Info</a></p>' +
                                          '<p>' + event['location'] + '</p>';
                event_list.appendChild(event_element);
            }
        };

        function update_events() {
            var days = document.getElementById('days').value;
            var max_results = document.getElementById('max-results').value;
            var message = {
                'days': days,
                'max_results': max_results
            };
            ws.send(JSON.stringify(message));
        }
    </script>
</head>
<body>
    <h1>Events in {{ city }}</h1>
    <p>Days: <input type="number" id="days" value="14"></p>
    <p>Max Results: <input type="number" id="max-results" value="5"></p>
    <button onclick="update_events()">Update</button>
    <div id="event-list"></div>
</body>
</html>

consumers.py

import json
from channels.generic.websocket import AsyncWebsocketConsumer
import requests

class EventConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.city = self.scope['url_route']['kwargs']['city']
        await self.channel_layer.group_add(
            self.city,
            self.channel_name
        )
        await self.accept()

    async def disconnect(self, close_code):
        await self.channel_layer.group_discard(
            self.city,
            self.channel_name
        )

    async def receive(self, text_data):
        url = "https://chicmi.p.rapidapi.com/calendar_in_city/"
        headers = {
            "X-RapidAPI-Key": "d4ba369aa5msh31ba822955b0a7bp1c2147jsn0b48eb6cab4f",
            "X-RapidAPI-Host": "chicmi.p.rapidapi.com"
        }
        response = requests.get(url, headers=headers)
        data = response.json()
        events = data["values"]["events"]
        event_data = []
        for event in events:
            event_data.append({
                "event_name": event["event_name"],
                "event_preview_url": event["event_preview_url"],
                "detail_url": event["detail_url"],
                "location": event["location"]
            })
        await self.channel_layer.group_send(
            self.city,
            {
                'type': 'send_event_data',
                'event_data': event_data
            }
        )

    async def send_event_data(self, event):
        event_data = event['event_data']
        await self.send(json.dumps({
            'event_data': event_data
        }))

routing.py

from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import path
from . import consumers

websocket_urlpatterns = [
    path('ws/<str:city>/', consumers.EventConsumer.as_asgi()),
]


application = ProtocolTypeRouter({
    "websocket": URLRouter(websocket_urlpatterns)
})

fashionShows/urls

from django.urls import path
from . import views

urlpatterns = [
    path('events/<str:city>/', views.events, name='events'),
]

views.py

from django.shortcuts import render

def events(request, city):
    return render(request, 'events.html', {'city': city})

asgi.py


os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'semWork.settings')

application = get_asgi_application()

Karina
  • 1
  • 1
  • You need to move `application` from routing.py to asgi.py and make `get_asgi_application()` the http handler in `ProtocolTypeRouter`. See my answer here https://stackoverflow.com/a/68231046/8238485 – Konstantin K. May 12 '23 at 01:30
  • I fixed my asgi import os from channel.routing import Protocol Type Router, URL Router from django.core.asgi import get_asgi_application from fashionShows import routing os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'semWork.settings') application = ProtocolTypeRouter({ "http": get_asgi_application(), "websocket": URLRouter(routing.websocket_urlpatterns), }) but it still doesn't work – Karina May 12 '23 at 13:13
  • I can get a websocket connection with the code you have provided by starting a completely new project and making the change I suggested. The problem must be elsewhere in your configuration that you haven't specified. Your logs look like they come from `nginx`. Is your `nginx` configured to do a protocol switch to websocket? https://nginx.org/en/docs/http/websocket.html – Konstantin K. May 12 '23 at 22:38
  • It could be that the problem lies in the incorrect launch of your Django project. Could you please guide me on how to do it correctly and what needs to be added to my code to make it work like yours? I am new to Django and need to finish this project on time. – Karina May 12 '23 at 23:32
  • And if it's not too much trouble, is it possible to not use nginx? I want to simplify this code but keep the same functionality. Thank you for your help! – Karina May 12 '23 at 23:49
  • I followed the [django-channels installation guide](https://channels.readthedocs.io/en/stable/installation.html) and used `manage.py runserver` to run the code, that's all. The use of `nginx` depends on what you're going to do with this project. If you only run it locally then `runserver` is fine. If you're planning to deploy it somewhere, then `runserver` is not suitable and you should have `nginx` or something similar (and [several other things](https://docs.djangoproject.com/en/4.2/howto/deployment/)). – Konstantin K. May 14 '23 at 04:33

0 Answers0