Loading
David Fernando Zuluaga
This is a live streamed presentation. You will automatically follow the presenter and see the slide they're currently on.
Web asíncrona con Django Channels
David Fernando Zuluaga A
@David_fza
@dafer154
zuluaaristi@gmail.com
Django channels y sus conceptos
Ejemplo de Django Channels
Desglosando el código
Preguntas
HTTP sessions y Django auth
V1.0
V2.0
Documentación
https://channels.readthedocs.io/en/stable/index.html
CARACTERÍSTICAS
Un código síncrono es aquel código donde cada instrucción espera a la anterior
Síncrono
Asíncrono
Documentación
https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne");
exampleSocket.onopen = function (event) {
exampleSocket.send("Here's some text that the server is urgently awaiting!");
};
//Se recibe el mensaje desde el servidor
exampleSocket.onmessage = function (event) {
console.log(event.data);
}
exampleSocket.close();
Explicacion
https://developer.mozilla.org/es/docs/WebSockets-840092-dup/Writing_WebSocket_client_applications
ASGI también está diseñado para ser un superconjunto de WSGI, permitiendo que las aplicaciones WSGI se ejecuten dentro de los servidores ASGI
Este es usado para el direccionamiento de las url que permiten tener conexión con los websockets
Puede combinar múltiples consumers (que son sus propias aplicaciones ASGI) en una aplicación más grande que represente su proyecto mediante routing
Un router solo puede tener un consumer para una conexión determinada.
from django.conf.urls import url
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from chat.consumers import AdminChatConsumer, PublicChatConsumer
from aprs_news.consumers import APRSNewsConsumer
application = ProtocolTypeRouter({
# WebSocket chat handler
"websocket": AuthMiddlewareStack(
URLRouter([
url(r"^chat/$", PublicChatConsumer),
])
),
})
Routing.py
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": [("redis-server-name", 6379)],
},
},
}
settings.py
Redis es la capa de canal que utiliza Django-channels para la transmisión de los mensajes en tiempo real.
Las capas de canal tienen una interfaz puramente asíncrona.
Mantiene la información en memoria
Permite escribir código síncrono o asíncrono
Se manejan distintos Consumers: SyncConsumer, WebsocketConsumer, AsyncWebSocketConsumer, JsonWebsocketConsumer y otros mas
from channels.generic.websocket import WebsocketConsumer
class MyConsumer(WebsocketConsumer):
groups = ["broadcast"]
def connect(self):
self.accept()
self.accept("subprotocol")
# To reject the connection, call:
self.close()
def receive(self, text_data=None, bytes_data=None):
# Called with either text_data or bytes_data for each frame
# You can call:
self.send(text_data="Hello world!")
# Want to force-close the connection? Call:
self.close()
def disconnect(self, close_code):
# Called when the socket closes
consumer.py
Ejemplo de aplicación
https://github.com/dafer154/questions-realTime
...
INSTALLED_APPS = [
'channels',
'bootstrap3',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'usuarios',
'preguntas'
]
...
WSGI_APPLICATION = 'QuestionsRT.wsgi.application'
ASGI_APPLICATION = 'QuestionsRT.routing.application'
.....
CHANNEL_LAYERS = {
"default": {
"BACKEND": "channels_redis.core.RedisChannelLayer",
"CONFIG": {
"hosts": ['redis://localhost:6379/4']
},
},
}
Settings.py
from django.urls import path
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from preguntas.consumers import ClassroomVirtual
websocket_urlpatterns = [
path("classroom/stream", ClassroomVirtual),
]
application = ProtocolTypeRouter({
"websocket": AuthMiddlewareStack(
URLRouter(
websocket_urlpatterns
),
),
})
Routing.py
from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer
import json
from .models import Pregunta
class ClassroomVirtual(WebsocketConsumer):
def connect(self):
async_to_sync(self.channel_layer.group_add)("chat", self.channel_name)
self.accept()
Consumer.py
...
class ClassroomVirtual(WebsocketConsumer):
def connect(self):
....
def receive(self, text_data):
pregunta = Pregunta.objects.get(pk=text_data)
data = {
'pregunta': str(pregunta.pregunta),
'falso': str('Falso'),
'verdadero': str('Verdadero'),
'id_pregunta': int(pregunta.id),
'tipo': str('Pregunta de Falso o Verdadero')
}
async_to_sync(self.channel_layer.group_send)(
"chat",
{
'type': 'chat_message',
'message': data
}
)
Consumer.py
...
class ClassroomVirtual(WebsocketConsumer):
def connect(self):
....
def receive(self, text_data):
....
# @def chat_message: metodo que recoge el Json Data y lo envia de nuevo a la pagina web,
# para que este sea visualizado a todos los usuarios que estan dentro de la Url
def chat_message(self, event):
message = event['message']
self.send(text_data=json.dumps(message))
# @def disconnect: metodo que permite desconectarse del websocket
def disconnect(self, close_code):
async_to_sync(self.channel_layer.group_discard)("chat", self.channel_name)
Consumer.py
....
from .models import Pregunta
class ClassroomVirtual(WebsocketConsumer):
def connect(self):
async_to_sync(self.channel_layer.group_add)("chat", self.channel_name)
self.accept()
def receive(self, text_data):
pregunta = Pregunta.objects.get(pk=text_data)
data = {
'pregunta': str(pregunta.pregunta),
'falso': str('Falso'),
'verdadero': str('Verdadero'),
'id_pregunta': int(pregunta.id),
'tipo': str('Pregunta de Falso o Verdadero')
}
async_to_sync(self.channel_layer.group_send)(
"chat",
{
'type': 'chat_message',
'message': data
}
)
def chat_message(self, event):
message = event['message']
self.send(text_data=json.dumps(message))
def disconnect(self, close_code):
async_to_sync(self.channel_layer.group_discard)("chat", self.channel_name)
<script>
$(function () {
var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
var ws_path = ws_scheme + '://' + window.location.host + "/classroom/stream";
var socket = new ReconnectingWebSocket(ws_path);
socket.onopen = function() {
console.log("Hello everywhere")
}
if (socket.readyState == WebSocket.OPEN) socket.onopen();
$(".btn-pregunta").on('click', function(event){
var id_pregunta = $(this).data("id");
socket.send(id_pregunta);
});
socket.onmessage = function (message) {
var data = JSON.parse(message.data);
};
socket.onclose = function () {
console.log("Desconectado");
}
});
</script>
pregunta_list.html