-
Notifications
You must be signed in to change notification settings - Fork 127
Description
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
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()
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
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'
(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!