Skip to content

Non-Firebase bugs - happy to help fix #173

@RobertNewton-Nomura

Description

@RobertNewton-Nomura

Hi; love the project!

Just want to preface this with the fact I'm pretty new to Django, and basically everything I'm talking about here I've figured out from trial and error, so there is more than likely some significant errors in my logic. I also based my changes directly from the documentation, which in some cases may be overly simplistic or not as fit for purpose as what is written, however I'm unable to ascertain whether or not this is the case due to my inexperience. Therefore, please accept my apology for any ignorant suggestions, and I'd greatly appreciate being corrected.

That said, I've been using the web version a bit without using Firebase found a few different issues, as followed. I'm very aware that a lot of the issues with channels may be caused by me not using Firebase, however I'd prefer to arrange the backend myself, and thought others may also want to do the same.

1. Issues with Generic Relations
When creating a GenericForeignKey the model comes out as:

class Tags(models.Model):

    # Relationships
    content_type = models.ForeignKey("contenttypes.ContentType", on_delete=models.CASCADE, related_query_name='tags' )

    # Fields
    object_id = models.IntegerField()
    created = models.DateTimeField(auto_now_add=True, editable=False)
    slug = models.SlugField()
    tag = models.CharField(max_length=30)
    last_updated = models.DateTimeField(auto_now=True, editable=False)
    link = models.GenericForeignKey("content_type", "object_id")

There are two missing imports, and two uses which need adjusting, namely ContentType and GenericForeignKey are both recommended to be imported, then called, eg:

from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class Tags(models.Model):

    # Relationships
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, related_query_name='tags' )

    # Fields
    object_id = models.IntegerField()
    created = models.DateTimeField(auto_now_add=True, editable=False)
    slug = models.SlugField()
    tag = models.CharField(max_length=30)
    last_updated = models.DateTimeField(auto_now=True, editable=False)
    link = GenericForeignKey("content_type", "object_id")


2. Issues with creating user models
When creating a User model, AbstractUser is not imported in the models, this would require

from django.contrib.auth.models import AbstractUser

In addition, if one is creating their own user model using AbstractUser, then they need to name it as such in the settings file:

AUTH_USER_MODEL = "User_App_Name.User_Model_Name"

This would then enable py manage.py makemigrations to be ran, and the server launched.


3. Django Channels Issues

Following the server launch, HTMX works (thank you for adding this! An unreal addition!), however Django Channels doesn't work as expected, getting the following:

Not Found: /ws/ [24/Nov/2022 08:13:36] "GET /ws/ HTTP/1.1" 404 2532
image

After doing some digging, I found that the depreciated django.conf.urls.url() is used in the routing.py file, however this was removed in 4.0.

When exploring the Django Channels documentation to try to figure out this issue, I came across a few things:

Firstly, I found that the depreciated django.conf.urls.url() is used in the routing.py file, however this was removed in 4.0.

In an attempt to solve this, I toyed around with using re_path instead, however this doesn't function as hoped with the existing code.

Secondly, the asgi and routing files are quite different in structure to the recommended docs (though I'm aware the docs I'm referencing are very simplistic and its possible that things can be done differently - please explain the logic behind doing so if that's the case!)

asgi.py on download:

"""
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

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "Journey1.settings")
django.setup()
application = get_default_application()

doc recommended asgi.py

import os

from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.security.websocket import AllowedHostsOriginValidator
from django.core.asgi import get_asgi_application
from django.urls import path

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "mysite.settings")
# Initialize Django ASGI application early to ensure the AppRegistry
# is populated before importing code that may import ORM models.
django_asgi_app = get_asgi_application()

from chat.consumers import AdminChatConsumer, PublicChatConsumer

application = ProtocolTypeRouter({
    # Django's ASGI application to handle traditional HTTP requests
    "http": django_asgi_app,

    # WebSocket chat handler
    "websocket": AllowedHostsOriginValidator(
        AuthMiddlewareStack(
            URLRouter([
                path("chat/admin/", AdminChatConsumer.as_asgi()),
                path("chat/", PublicChatConsumer.as_asgi()),
            ])
        )
    ),
})

routing.py on download

from django.conf.urls import url

from channels.routing import ChannelNameRouter, ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack

from Journey1.consumers import Journey1_WebSocketConsumer

# Consumer Imports
from Events.consumers import EventsConsumer
from User.consumers import UserConsumer


application = ProtocolTypeRouter({

    # WebSocket handler
    "websocket": AuthMiddlewareStack(
        URLRouter([
            url(r"^ws/$", Journey1_WebSocketConsumer.as_asgi()),
        ])
    ),
    "channel": ChannelNameRouter({
        "Events": EventsConsumer,    "User": UserConsumer,
    })
})

doc recommended routing - This documentation also discusses the use of re_path instead of url:

# chat/routing.py
from django.urls import re_path

from . import consumers

websocket_urlpatterns = [
    re_path(r"ws/chat/(?P<room_name>\w+)/$", consumers.ChatConsumer.as_asgi()),
]

From what I can see it seems that some of the functions, namely ProtocolTypeRouter is in the routing.py file, rather than the asgi.py as recommended. Other than the differing structure, there is the addition use of AllowedHostsOriginValidator in the docs.

I followed the recommended format seen in the documentation, adjusting imports from
from Journey1.consumers import Journey1_WebSocketConsumer (in routing.py) & from Journey1.routing import application (in asgi.py)
to
from .consumers import Journey1_WebSocketConsumer & from .routing import application

Setting up daphne

Including changing the settings.py to follow channels set up guidelines:

# Application definition INSTALLED_APPS = [ 'django.contrib.admin',...

to

# Application definition INSTALLED_APPS = [ "daphne", 'django.contrib.admin',

ASGI_APPLICATION = "Journey1.routing.application"
to
ASGI_APPLICATION = "Journey1.asgi.application"

Then the server & channels function as expected, without the /ws/ 404 bug.

Starting ASGI/Daphne version 4.0.0 development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
HTTP GET / 200 [0.03, 127.0.0.1:52304]
WebSocket HANDSHAKING /ws/ [127.0.0.1:52310]
WebSocket CONNECT /ws/ [127.0.0.1:52310]
Received text=Text from Javascript
Received bytes=b'Bytes from Javascript'

image

(the closed port error is related to chrome extensions)


I've taken a look into the files, and think that I might be able to tackle some of the issues which are contained in the python files, however some of the population issues are a little more complex (for example the conditional imports of GenericForeignKey / ContentType / AbstractUser).

Curious to hear your thoughts on the above, and totally understand if you don't have interest in pulling the above as it goes against your choice of using firebase, though perhaps some of the issues may persist across on to firebase implementations as well.

Thanks for reading!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions