Como Integrar o Django Com os Canais Do Django

Neste tutorial, construiremos um aplicativo de bate-papo em tempo real com o Django Channels , focando em como integrar o Django com o Django Channels.

Por que outro aplicativo de bate-papo? Bem, um aplicativo de bate-papo é a maneira mais fácil de mostrar o poder dos canais. Dito isso, este tutorial vai além do básico, implementando vários tipos de solicitação, persistência de mensagem/sala de bate-papo e mensagens privadas (um para um). Depois de passar pelo tutorial, você poderá criar aplicativos em tempo real.

O que é o Django Channels?

O Django Channels (ou apenas Channels) estende os recursos internos do Django , permitindo que os projetos do Django lidem não apenas com HTTP, mas também com protocolos que exigem conexões de longa duração, como WebSockets, MQTT (IoT), chatbots, rádios e outros recursos reais. aplicações de tempo. Além disso, ele fornece suporte para vários recursos principais do Django, como autenticação e sessões.

Uma configuração básica de canais se parece com isto:

Estrutura básica do Django + Canais

Para saber mais sobre os Canais, confira o guia de introdução na documentação oficial .

Sincronização vs Assíncrona

Por causa das diferenças entre Channels e Django, teremos que alternar frequentemente entre execução de código sincronizado e assíncrono. Por exemplo, o banco de dados Django precisa ser acessado usando código síncrono, enquanto a camada de canal Canais precisa ser acessada usando código assíncrono.

A maneira mais fácil de alternar entre os dois é usando as funções internas do Django asgiref ( asgrief.sync):

  1. sync_to_async- pega uma função de sincronização e retorna uma função assíncrona que a envolve
  2. async_to_sync- pega uma função assíncrona e retorna uma função de sincronização

Não se preocupe com isso ainda, vamos mostrar um exemplo prático mais adiante no tutorial.

Configuração do projeto

Novamente, estaremos construindo um aplicativo de bate-papo. O aplicativo terá várias salas onde os usuários autenticados pelo Django podem conversar. Cada sala terá uma lista de usuários atualmente conectados. Também implementaremos mensagens privadas e individuais.

Configuração do projeto Django

Comece criando um novo diretório e configurando um novo projeto Django:

$ mkdir django-channels-example && cd django-channels-example
$ python3.9 -m venv env
$ source env/bin/activate

(env)$ pip install django==4.0
(env)$ django-admin startproject core .

Depois disso, crie um novo aplicativo Django chamado chat:

(env)$ python manage.py startapp chat

Registre o aplicativo em core/settings.py em INSTALLED_APPS:

# core/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'chat.apps.ChatConfig',  # new
]

Criar modelos de banco de dados

Em seguida, vamos criar dois modelos Django, Roome Message, em chat/models.py :

# chat/models.py

from django.contrib.auth.models import User
from django.db import models


class Room(models.Model):
    name = models.CharField(max_length=128)
    online = models.ManyToManyField(to=User, blank=True)

    def get_online_count(self):
        return self.online.count()

    def join(self, user):
        self.online.add(user)
        self.save()

    def leave(self, user):
        self.online.remove(user)
        self.save()

    def __str__(self):
        return f'{self.name} ({self.get_online_count()})'


class Message(models.Model):
    user = models.ForeignKey(to=User, on_delete=models.CASCADE)
    room = models.ForeignKey(to=Room, on_delete=models.CASCADE)
    content = models.CharField(max_length=512)
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'{self.user.username}: {self.content} [{self.timestamp}]'

Notas:

  1. Roomrepresenta uma sala de bate-papo. Ele contém um onlinecampo para rastrear quando os usuários se conectam e se desconectam da sala de bate-papo.
  2. Messagerepresenta uma mensagem enviada para a sala de chat. Usaremos este modelo para armazenar todas as mensagens enviadas no chat.

Execute os comandos makemigrationse para sincronizar o banco de dados:migrate

(env)$ python manage.py makemigrations
(env)$ python manage.py migrate

Registre os modelos em chat/admin.py para que fiquem acessíveis no painel de administração do Django:

# chat/admin.py

from django.contrib import admin

from chat.models import Room, Message

admin.site.register(Room)
admin.site.register(Message)

Visualizações e URLs

O aplicativo da web terá os dois URLs a seguir:

  1. /chat/- seletor de sala de bate-papo
  2. /chat/<ROOM_NAME>/- sala de bate-papo

Adicione as seguintes visualizações a chat/views.py :

# chat/views.py

from django.shortcuts import render

from chat.models import Room


def index_view(request):
    return render(request, 'index.html', {
        'rooms': Room.objects.all(),
    })


def room_view(request, room_name):
    chat_room, created = Room.objects.get_or_create(name=room_name)
    return render(request, 'room.html', {
        'room': chat_room,
    })

Crie um arquivo urls.py dentro do chataplicativo:

# chat/urls.py

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index_view, name='chat-index'),
    path('<str:room_name>/', views.room_view, name='chat-room'),
]

Atualize também o arquivo urls.py no nível do projeto com o chataplicativo:

# core/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('chat/', include('chat.urls')),  # new
    path('admin/', admin.site.urls),
]

Modelos e arquivos estáticos

Crie um arquivo index.html dentro de uma nova pasta chamada "templates" em "chat":

<!-- chat/templates/index.html -->

{% load static %}

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>django-channels-chat</title>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css">
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"></script>
        <style>
            #roomSelect {
                height: 300px;
            }
        </style>
    </head>
    <body>
        <div class="container mt-3 p-5">
            <h2>django-channels-chat</h2>
            <div class="row">
                <div class="col-12 col-md-8">
                    <div class="mb-2">
                        <label for="roomInput">Enter a room name to connect to it:</label>
                        <input type="text" class="form-control" id="roomInput" placeholder="Room name">
                        <small id="roomInputHelp" class="form-text text-muted">If the room doesn't exist yet, it will be created for you.</small>
                    </div>
                    <button type="button" id="roomConnect" class="btn btn-success">Connect</button>
                </div>
                <div class="col-12 col-md-4">
                    <label for="roomSelect">Active rooms</label>
                    <select multiple class="form-control" id="roomSelect">
                        {% for room in rooms %}
                            <option>{{ room }}</option>
                        {% endfor %}
                    </select>
                </div>
            </div>
        </div>
        <script src="{% static 'index.js' %}"></script>
    </body>
</html>

Em seguida, adicione room.html dentro da mesma pasta:

<!-- chat/templates/room.html -->

{% load static %}

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>django-channels-chat</title>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css">
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"></script>
        <style>
            #chatLog {
                height: 300px;
                background-color: #FFFFFF;
                resize: none;
            }

            #onlineUsersSelector {
                height: 300px;
            }
        </style>
    </head>
    <body>
        <div class="container mt-3 p-5">
            <h2>django-channels-chat</h2>
            <div class="row">
                <div class="col-12 col-md-8">
                    <div class="mb-2">
                        <label for="chatLog">Room: #{{ room.name }}</label>
                        <textarea class="form-control" id="chatLog" readonly></textarea>
                    </div>
                    <div class="input-group">
                        <input type="text" class="form-control" id="chatMessageInput" placeholder="Enter your chat message">
                        <div class="input-group-append">
                            <button class="btn btn-success" id="chatMessageSend" type="button">Send</button>
                        </div>
                    </div>
                </div>
                <div class="col-12 col-md-4">
                    <label for="onlineUsers">Online users</label>
                    <select multiple class="form-control" id="onlineUsersSelector">
                    </select>
                </div>
            </div>
            {{ room.name|json_script:"roomName" }}
        </div>
        <script src="{% static 'room.js' %}"></script>
    </body>
</html>

Para tornar nosso código mais legível, incluiremos o código JavaScript em arquivos separados -- index.js e room.js , respectivamente. Como não podemos acessar o contexto do Django em JavaScript, podemos usar a tag de modelo json_script para armazená room.name-lo e buscá-lo no arquivo JavaScript.

Dentro de "chat", crie uma pasta chamada "static". Em seguida, dentro de "static", crie um arquivo index.js e um arquivo room.js.

index.js :

// chat/static/index.js

console.log("Sanity check from index.js.");

// focus 'roomInput' when user opens the page
document.querySelector("#roomInput").focus();

// submit if the user presses the enter key
document.querySelector("#roomInput").onkeyup = function(e) {
    if (e.keyCode === 13) {  // enter key
        document.querySelector("#roomConnect").click();
    }
};

// redirect to '/room/<roomInput>/'
document.querySelector("#roomConnect").onclick = function() {
    let roomName = document.querySelector("#roomInput").value;
    window.location.pathname = "chat/" + roomName + "/";
}

// redirect to '/room/<roomSelect>/'
document.querySelector("#roomSelect").onchange = function() {
    let roomName = document.querySelector("#roomSelect").value.split(" (")[0];
    window.location.pathname = "chat/" + roomName + "/";
}

sala.js :

// chat/static/room.js

console.log("Sanity check from room.js.");

const roomName = JSON.parse(document.getElementById('roomName').textContent);

let chatLog = document.querySelector("#chatLog");
let chatMessageInput = document.querySelector("#chatMessageInput");
let chatMessageSend = document.querySelector("#chatMessageSend");
let onlineUsersSelector = document.querySelector("#onlineUsersSelector");

// adds a new option to 'onlineUsersSelector'
function onlineUsersSelectorAdd(value) {
    if (document.querySelector("option[value='" + value + "']")) return;
    let newOption = document.createElement("option");
    newOption.value = value;
    newOption.innerHTML = value;
    onlineUsersSelector.appendChild(newOption);
}

// removes an option from 'onlineUsersSelector'
function onlineUsersSelectorRemove(value) {
    let oldOption = document.querySelector("option[value='" + value + "']");
    if (oldOption !== null) oldOption.remove();
}

// focus 'chatMessageInput' when user opens the page
chatMessageInput.focus();

// submit if the user presses the enter key
chatMessageInput.onkeyup = function(e) {
    if (e.keyCode === 13) {  // enter key
        chatMessageSend.click();
    }
};

// clear the 'chatMessageInput' and forward the message
chatMessageSend.onclick = function() {
    if (chatMessageInput.value.length === 0) return;
    // TODO: forward the message to the WebSocket
    chatMessageInput.value = "";
};

Sua estrutura final de diretórios do aplicativo "chat" deve ficar assim:

chat
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│   ├── 0001_initial.py
│   ├── __init__.py
├── models.py
├── static
│   ├── index.js
│   └── room.js
├── templates
│   ├── index.html
│   └── room.html
├── tests.py
├── urls.py
└── views.py

Teste

Com a configuração básica do projeto, vamos testar as coisas no navegador.

Inicie o servidor de desenvolvimento Django:

(env)$ python manage.py runserver

Navegue até http://localhost:8000/chat/ . Você verá o seletor de sala:

Seletor de Sala dos Canais do Django

Para garantir que os arquivos estáticos estejam configurados corretamente, abra o 'Console do desenvolvedor'. Você deve ver a verificação de sanidade:

Sanity check from index.js.

Em seguida, digite algo na entrada de texto 'Nome da sala' e pressione enter. Você será redirecionado para a sala:

Seletor de Sala dos Canais do Django

Estes são apenas modelos estáticos. Implementaremos a funcionalidade para o chat e usuários online mais tarde.

Adicionar canais

Em seguida, vamos conectar os canais do Django.

Comece instalando o pacote:

(env)$ pip install channels==3.0.4

Em seguida, adicione channelsao seu INSTALLED_APPSinterior core/settings.py :

# core/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'chat.apps.ChatConfig',
    'channels',  # new
]

Como usaremos WebSockets em vez de HTTP para comunicar do cliente para o servidor, precisamos envolver nossa configuração ASGI com ProtocolTypeRouter em core/asgi.py :

# core/asgi.py

import os

from channels.routing import ProtocolTypeRouter
from django.core.asgi import get_asgi_application

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

application = ProtocolTypeRouter({
  'http': get_asgi_application(),
})

Este roteador roteará o tráfego para diferentes partes do aplicativo da Web, dependendo do protocolo usado.

As versões do Django <= 2.2 não possuem suporte ASGI embutido. Para channelsrodar com versões mais antigas do Django, consulte o guia de instalação oficial .

Em seguida, precisamos informar ao Django a localização do nosso aplicativo ASGI. Adicione o seguinte ao seu arquivo core/settings.py , logo abaixo da WSGI_APPLICATIONconfiguração:

# core/settings.py

WSGI_APPLICATION = 'core.wsgi.application'
ASGI_APPLICATION = 'core.asgi.application'  # new

Ao executar o servidor de desenvolvimento agora, você verá que os canais estão sendo usados:

Starting ASGI/Channels version 3.0.4 development server at http://127.0.0.1:8000/

Adicionar camada de canal

Uma camada de canal é um tipo de sistema de comunicação, que permite que várias partes do nosso aplicativo troquem mensagens, sem transportar todas as mensagens ou eventos pelo banco de dados.

Precisamos de uma camada de canal para dar aos consumidores (que implementaremos na próxima etapa) a capacidade de conversar uns com os outros.

Embora possamos usar a camada InMemoryChannelLayer já que estamos no modo de desenvolvimento, usaremos uma camada pronta para produção, RedisChannelLayer .

Como essa camada requer Redis , execute o seguinte comando para colocá-la em funcionamento com o Docker :

(env)$ docker run -p 6379:6379 -d redis:5

Este comando baixa a imagem e ativa um contêiner Redis Docker na porta 6379.

Se você não quiser usar o Docker, sinta-se à vontade para baixar o Redis diretamente do site oficial .

Para se conectar ao Redis a partir do Django, precisamos instalar um pacote adicional chamado channels_redis :

(env)$ pip install channels_redis==3.3.1

Depois disso, configure a camada em core/settings.py assim:

# core/settings.py

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}

Aqui, informamos a channels_redis onde o servidor Redis está localizado.

Para testar se tudo funciona como esperado, abra o shell do Django:

(env)$ python manage.py shell

Então corra:

>>> import channels.layers
>>> channel_layer = channels.layers.get_channel_layer()
>>>
>>> from asgiref.sync import async_to_sync
>>> async_to_sync(channel_layer.send)('test_channel', {'type': 'hello'})
>>> async_to_sync(channel_layer.receive)('test_channel')
{'type': 'hello'}

Aqui, nos conectamos à camada de canal usando as configurações definidas em core/settings.py . Em seguida, costumávamos channel_layer.sendenviar uma mensagem ao test_channelgrupo e channel_layer.receiveler todas as mensagens enviadas ao mesmo grupo.

Observe que agrupamos todas as chamadas de função async_to_syncporque a camada de canal é assíncrona.

Enter quit()para sair do shell.

Adicionar consumidor de canais

Um consumidor é a unidade básica do código de Canais. Eles são pequenos aplicativos ASGI, dirigidos por eventos. Eles são semelhantes às visualizações do Django. No entanto, ao contrário das visualizações do Django, os consumidores são de longa duração por padrão. Um projeto Django pode ter vários consumidores que são combinados usando roteamento de canais (que veremos na próxima seção).

Cada consumidor tem seu próprio escopo, que é um conjunto de detalhes sobre uma única conexão de entrada. Eles contêm dados como tipo de protocolo, caminho, cabeçalhos, argumentos de roteamento, agente do usuário e muito mais.

Crie um novo arquivo chamado consumer.py dentro de "chat":

# chat/consumers.py

import json

from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer

from .models import Room


class ChatConsumer(WebsocketConsumer):

    def __init__(self, *args, **kwargs):
        super().__init__(args, kwargs)
        self.room_name = None
        self.room_group_name = None
        self.room = None

    def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = f'chat_{self.room_name}'
        self.room = Room.objects.get(name=self.room_name)

        # connection has to be accepted
        self.accept()

        # join the room group
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name,
        )

    def disconnect(self, close_code):
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name,
        )

    def receive(self, text_data=None, bytes_data=None):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        # send chat message event to the room
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message,
            }
        )

    def chat_message(self, event):
        self.send(text_data=json.dumps(event))

Aqui, criamos um ChatConsumer, que herda de WebsocketConsumer . WebsocketConsumerfornece três métodos, connect(), disconnect()e receive():

  1. No interior connect()ligamos accept()para aceitar a conexão. Depois disso, adicionamos o usuário ao grupo de camadas do canal.
  2. Dentro disconnect()nós removemos o usuário do grupo de camadas do canal.
  3. Dentro receive(), analisamos os dados para JSON e extraímos o arquivo message. Em seguida, encaminhamos o messageuso group_sendpara chat_message.

Ao usar a camada do canal group_send, seu consumidor precisa ter um método para cada mensagem JSON que typevocê usa. Na nossa situação, typeé igual a chat_message. Assim, adicionamos um método chamado chat_message.

Se você usar pontos em seus tipos de mensagem, os Canais os converterão automaticamente em sublinhados ao procurar um método - por exemplo, chat.messagese tornará chat_message.

Como WebsocketConsumeré um consumidor síncrono, tivemos que chamar async_to_syncao trabalhar com a camada de canal. Decidimos usar um consumidor de sincronização, já que o aplicativo de bate-papo está intimamente conectado ao Django (que é sincronizado por padrão). Em outras palavras, não obteríamos um aumento de desempenho usando um consumidor assíncrono.

Você deve usar consumidores de sincronização por padrão. Além do mais, use apenas consumidores assíncronos nos casos em que você está absolutamente certo de que está fazendo algo que se beneficiaria do tratamento assíncrono (por exemplo, tarefas de longa duração que podem ser feitas em paralelo) e você está usando apenas async-native bibliotecas.

Adicionar roteamento de canais

Channels fornece diferentes classes de roteamento que nos permitem combinar e empilhar consumidores. Eles são semelhantes aos URLs do Django.

Adicione um arquivo routing.py ao "chat":

# 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()),
]

Registre o arquivo routing.py dentro de core/asgi.py :

# core/asgi.py

import os

from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application

import chat.routing

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

application = ProtocolTypeRouter({
  'http': get_asgi_application(),
  'websocket': URLRouter(
      chat.routing.websocket_urlpatterns
    ),
})

WebSockets (front-end)

Para se comunicar com os canais do frontend, usaremos a API WebSocket .

WebSockets são extremamente fáceis de usar. Primeiro, você precisa estabelecer uma conexão fornecendo um urle, em seguida, poderá ouvir os seguintes eventos:

  1. onopen- chamado quando uma conexão WebSocket é estabelecida
  2. onclose- chamado quando uma conexão WebSocket é destruída
  3. onmessage- chamado quando um WebSocket recebe uma mensagem
  4. onerror- chamado quando um WebSocket encontra um erro

Para integrar WebSockets ao aplicativo, adicione o seguinte à parte inferior de room.js :

// chat/static/room.js

let chatSocket = null;

function connect() {
    chatSocket = new WebSocket("ws://" + window.location.host + "/ws/chat/" + roomName + "/");

    chatSocket.onopen = function(e) {
        console.log("Successfully connected to the WebSocket.");
    }

    chatSocket.onclose = function(e) {
        console.log("WebSocket connection closed unexpectedly. Trying to reconnect in 2s...");
        setTimeout(function() {
            console.log("Reconnecting...");
            connect();
        }, 2000);
    };

    chatSocket.onmessage = function(e) {
        const data = JSON.parse(e.data);
        console.log(data);

        switch (data.type) {
            case "chat_message":
                chatLog.value += data.message + "\n";
                break;
            default:
                console.error("Unknown message type!");
                break;
        }

        // scroll 'chatLog' to the bottom
        chatLog.scrollTop = chatLog.scrollHeight;
    };

    chatSocket.onerror = function(err) {
        console.log("WebSocket encountered an error: " + err.message);
        console.log("Closing the socket.");
        chatSocket.close();
    }
}
connect();

Após estabelecer a conexão WebSocket, no onmessagecaso, determinamos o tipo de mensagem com base em data.type. Observe como envolvemos o WebSocket dentro do connect()método para ter a capacidade de restabelecer a conexão caso ela caia.

Por fim, altere o TODO interno chatMessageSend.onclickFormpara o seguinte:

// chat/static/room.js

chatSocket.send(JSON.stringify({
    "message": chatMessageInput.value,
}));

O manipulador completo agora deve ficar assim:

// chat/static/room.js

chatMessageSend.onclick = function() {
    if (chatMessageInput.value.length === 0) return;
    chatSocket.send(JSON.stringify({
        "message": chatMessageInput.value,
    }));
    chatMessageInput.value = "";
};

A primeira versão do chat está pronta.

Para testar, execute o servidor de desenvolvimento. Em seguida, abra duas janelas de navegador privadas/anônimas e, em cada uma, navegue até http://localhost:8000/chat/default/ . Você deve ser capaz de enviar uma mensagem:

Teste de canais do Django

Isso é tudo para a funcionalidade básica. Em seguida, veremos a autenticação.

Autenticação

Processo interno

Channels vem com uma classe embutida para sessão Django e gerenciamento de autenticação chamada AuthMiddlewareStack.

Para usá-lo, a única coisa que precisamos fazer é envolver URLRouterdentro do core/asgi.py assim:

# core/asgi.py

import os

from channels.auth import AuthMiddlewareStack  # new import
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application

import chat.routing

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

application = ProtocolTypeRouter({
  'http': get_asgi_application(),
  'websocket': AuthMiddlewareStack(  # new
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),  # new
})

Agora, sempre que um cliente autenticado ingressar, o objeto de usuário será adicionado ao escopo. Ele pode ser acessado assim:

user = self.scope['user']

Se você deseja executar Canais com uma estrutura JavaScript de front-end (como Angular, React ou Vue), precisará usar um sistema de autenticação diferente (por exemplo, autenticação de token). Se você quiser aprender a usar a autenticação de token com os Canais, confira os seguintes cursos:

  1. Desenvolvendo um aplicativo de táxi em tempo real com canais Django e Angular
  2. Desenvolvendo um aplicativo de táxi em tempo real com Django Channels e React

Vamos modificar o ChatConsumerpara bloquear usuários não autenticados de falar e para exibir o nome de usuário do usuário com a mensagem.

Altere chat/consumers.py para o seguinte:

# chat/consumers.py

import json

from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer

from .models import Room, Message  # new import


class ChatConsumer(WebsocketConsumer):

    def __init__(self, *args, **kwargs):
        super().__init__(args, kwargs)
        self.room_name = None
        self.room_group_name = None
        self.room = None
        self.user = None  # new

    def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = f'chat_{self.room_name}'
        self.room = Room.objects.get(name=self.room_name)
        self.user = self.scope['user']  # new

        # connection has to be accepted
        self.accept()

        # join the room group
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name,
        )

    def disconnect(self, close_code):
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name,
        )

    def receive(self, text_data=None, bytes_data=None):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        if not self.user.is_authenticated:  # new
            return                          # new

        # send chat message event to the room
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'chat_message',
                'user': self.user.username,  # new
                'message': message,
            }
        )
        Message.objects.create(user=self.user, room=self.room, content=message)  # new

    def chat_message(self, event):
        self.send(text_data=json.dumps(event))

A parte dianteira

Em seguida, vamos modificar room.js para exibir o nome de usuário do usuário. Dentro chatSocket.onMessagede , adicione o seguinte:

// chat/static/room.js

chatSocket.onmessage = function(e) {
    const data = JSON.parse(e.data);
    console.log(data);

    switch (data.type) {
        case "chat_message":
            chatLog.value += data.user + ": " + data.message + "\n";  // new
            break;
        default:
            console.error("Unknown message type!");
            break;
    }

    // scroll 'chatLog' to the bottom
    chatLog.scrollTop = chatLog.scrollHeight;
};

Teste

Crie um superusuário, que você usará para testar:

(env)$ python manage.py createsuperuser

Execute o servidor:

(env)$ python manage.py runserver

Abra o navegador e faça login usando o login de administrador do Django em http://localhost:8000/admin .

Em seguida, navegue até http://localhost:8000/chat/default . Teste!

Canais do Django Bate-papo com Nomes de Usuário

Saia do administrador do Django. Navegue até http://localhost:8000/chat/default . O que acontece quando você tenta postar uma mensagem?

Mensagens do usuário

Em seguida, adicionaremos os três tipos de mensagem a seguir:

  1. user_list- enviado para o usuário recém-ingressado ( data.users= lista de usuários online)
  2. user_join- enviado quando um usuário entra em uma sala de bate-papo
  3. user_leave- enviado quando um usuário sai de uma sala de bate-papo

Processo interno

No final do connectmétodo, ChatConsumeradicione:

# chat/consumers.py

def connect(self):
    # ...

    # send the user list to the newly joined user
    self.send(json.dumps({
        'type': 'user_list',
        'users': [user.username for user in self.room.online.all()],
    }))

    if self.user.is_authenticated:
        # send the join event to the room
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'user_join',
                'user': self.user.username,
            }
        )
        self.room.online.add(self.user)

No final do disconnectmétodo, ChatConsumeradicione:

# chat/consumers.py

def disconnect(self, close_code):
    # ...

    if self.user.is_authenticated:
        # send the leave event to the room
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'user_leave',
                'user': self.user.username,
            }
        )
        self.room.online.remove(self.user)

Como adicionamos novos tipos de mensagem, também precisamos adicionar os métodos para a camada de canal. No final de chat/consumers.py adicione:

# chat/consumers.py

def user_join(self, event):
    self.send(text_data=json.dumps(event))

def user_leave(self, event):
    self.send(text_data=json.dumps(event))

Seu consumer.py após esta etapa deve ficar assim: consumer.py .

A parte dianteira

Para manipular as mensagens do frontend, adicione os seguintes casos à instrução switch no chatSocket.onmessagemanipulador:

// chat/static/room.js

switch (data.type) {
    // ...
    case "user_list":
        for (let i = 0; i < data.users.length; i++) {
            onlineUsersSelectorAdd(data.users[i]);
        }
        break;
    case "user_join":
        chatLog.value += data.user + " joined the room.\n";
        onlineUsersSelectorAdd(data.user);
        break;
    case "user_leave":
        chatLog.value += data.user + " left the room.\n";
        onlineUsersSelectorRemove(data.user);
        break;
    // ...

Teste

Execute o servidor novamente, faça login e visite http://localhost:8000/chat/default .

Mensagem de ingresso nos canais do Django

Agora você deve poder ver as mensagens de entrada e saída. A lista de usuários também deve ser preenchida.

Mensagens Privadas

O pacote Channels não permite filtragem direta, portanto, não há um método interno para enviar mensagens de um cliente para outro cliente. Com Canais, você pode enviar uma mensagem para:

  1. O cliente do consumidor ( self.send)
  2. Um grupo de camadas de canal ( self.channel_layer.group_send)

Assim, para implementar mensagens privadas, vamos:

  1. Crie um novo grupo chamado inbox_%USERNAME%sempre que um cliente ingressar.
  2. Adicione o cliente ao seu próprio grupo de caixa de entrada ( inbox_%USERNAME%).
  3. Remova o cliente de seu grupo de caixa de entrada ( inbox_%USERNAME%) quando ele se desconectar.

Uma vez implementado, cada cliente terá sua própria caixa de entrada para mensagens privadas. Outros clientes podem enviar mensagens privadas para inbox_%TARGET_USERNAME%.

Processo interno

Modifique chat/consumers.py .

# chat/consumers.py

class ChatConsumer(WebsocketConsumer):

    def __init__(self, *args, **kwargs):
        # ...
        self.user_inbox = None  # new

    def connect(self):
        # ...
        self.user_inbox = f'inbox_{self.user.username}'  # new

        # accept the incoming connection
        self.accept()

        # ...

        if self.user.is_authenticated:
            # -------------------- new --------------------
            # create a user inbox for private messages
            async_to_sync(self.channel_layer.group_add)(
                self.user_inbox,
                self.channel_name,
            )
            # ---------------- end of new ----------------
            # ...

    def disconnect(self, close_code):
        # ...

        if self.user.is_authenticated:
            # -------------------- new --------------------
            # delete the user inbox for private messages
            async_to_sync(self.channel_layer.group_add)(
                self.user_inbox,
                self.channel_name,
            )
            # ---------------- end of new ----------------
            # ...

Então, nós:

  1. Adicionado e inicializado user_inboxem .ChatConsumerconnect()
  2. Adicionado o usuário ao user_inboxgrupo quando ele se conecta.
  3. Removido o usuário do user_inboxgrupo quando ele se desconecta.

Em seguida, modifique receive()para lidar com mensagens privadas:

# chat/consumers.py

def receive(self, text_data=None, bytes_data=None):
    text_data_json = json.loads(text_data)
    message = text_data_json['message']

    if not self.user.is_authenticated:
        return

    # -------------------- new --------------------
    if message.startswith('/pm '):
        split = message.split(' ', 2)
        target = split[1]
        target_msg = split[2]

        # send private message to the target
        async_to_sync(self.channel_layer.group_send)(
            f'inbox_{target}',
            {
                'type': 'private_message',
                'user': self.user.username,
                'message': target_msg,
            }
        )
        # send private message delivered to the user
        self.send(json.dumps({
            'type': 'private_message_delivered',
            'target': target,
            'message': target_msg,
        }))
        return
    # ---------------- end of new ----------------

    # send chat message event to the room
    async_to_sync(self.channel_layer.group_send)(
        self.room_group_name,
        {
            'type': 'chat_message',
            'user': self.user.username,
            'message': message,
        }
    )
    Message.objects.create(user=self.user, room=self.room, content=message)

Adicione os seguintes métodos no final de chat/consumers.py :

# chat/consumers.py

def private_message(self, event):
    self.send(text_data=json.dumps(event))

def private_message_delivered(self, event):
    self.send(text_data=json.dumps(event))

Seu arquivo final chat/consumers.py deve ser igual a este: consumer.py

A parte dianteira

Para lidar com mensagens privadas no frontend, adicione private_messagee private_message_deliveredcases dentro da switch(data.type)instrução:

// chat/static/room.js

switch (data.type) {
    // ...
    case "private_message":
        chatLog.value += "PM from " + data.user + ": " + data.message + "\n";
        break;
    case "private_message_delivered":
        chatLog.value += "PM to " + data.target + ": " + data.message + "\n";
        break;
    // ...
}

Para tornar o chat um pouco mais conveniente, podemos alterar a entrada da mensagem para pm %USERNAME%quando o usuário clica em um dos usuários online no arquivo onlineUsersSelector. Adicione o seguinte manipulador à parte inferior:

// chat/static/room.js

onlineUsersSelector.onchange = function() {
    chatMessageInput.value = "/pm " + onlineUsersSelector.value + " ";
    onlineUsersSelector.value = null;
    chatMessageInput.focus();
};

Teste

É isso! O aplicativo cap agora está completo. Vamos testá-lo uma última vez.

Crie dois superusuários para teste e execute o servidor.

Abra dois navegadores privados/anônimos diferentes, fazendo login em ambos em http://localhost:8000/admin .

Em seguida, navegue até http://localhost:8000/chat/default em ambos os navegadores. Clique em um dos usuários conectados para enviar uma mensagem privada:

Versão final do bate-papo dos canais do Django

Conclusão

Neste tutorial, vimos como usar Canais com Django. Você aprendeu sobre as diferenças entre a execução de código síncrona e assíncrona junto com os conceitos dos canais a seguir:

  1. Consumidores
  2. Camadas do canal
  3. Roteamento

Por fim, juntamos tudo com o WebSockets e criamos um aplicativo de bate-papo.

Nosso bate-papo está longe de ser perfeito. Se você quiser praticar o que aprendeu, pode melhorá-lo:

  1. Adicionando salas de bate-papo somente para administradores.
  2. Enviando as últimas dez mensagens para o usuário quando ele entra em uma sala de bate-papo.
  3. Permitir que os usuários editem e excluam mensagens.
  4. Adicionando a funcionalidade '{user} está digitando'.
  5. Adicionando reações de mensagem.

As ideias são classificadas das mais fáceis para as mais difíceis de implementar.

Você pode pegar o código do repositório django-channels-example no GitHub.

Fonte:  https://testdrive.io

#django 

What is GEEK

Buddha Community

Como Integrar o Django Com os Canais Do Django
Ahebwe  Oscar

Ahebwe Oscar

1620177818

Django admin full Customization step by step

Welcome to my blog , hey everyone in this article you learn how to customize the Django app and view in the article you will know how to register  and unregister  models from the admin view how to add filtering how to add a custom input field, and a button that triggers an action on all objects and even how to change the look of your app and page using the Django suit package let’s get started.

Database

Custom Titles of Django Admin

Exclude in Django Admin

Fields in Django Admin

#django #create super user django #customize django admin dashboard #django admin #django admin custom field display #django admin customization #django admin full customization #django admin interface #django admin register all models #django customization

Ahebwe  Oscar

Ahebwe Oscar

1620185280

How model queries work in Django

How model queries work in Django

Welcome to my blog, hey everyone in this article we are going to be working with queries in Django so for any web app that you build your going to want to write a query so you can retrieve information from your database so in this article I’ll be showing you all the different ways that you can write queries and it should cover about 90% of the cases that you’ll have when you’re writing your code the other 10% depend on your specific use case you may have to get more complicated but for the most part what I cover in this article should be able to help you so let’s start with the model that I have I’ve already created it.

**Read More : **How to make Chatbot in Python.

Read More : Django Admin Full Customization step by step

let’s just get into this diagram that I made so in here:

django queries aboutDescribe each parameter in Django querset

we’re making a simple query for the myModel table so we want to pull out all the information in the database so we have this variable which is gonna hold a return value and we have our myModel models so this is simply the myModel model name so whatever you named your model just make sure you specify that and we’re gonna access the objects attribute once we get that object’s attribute we can simply use the all method and this will return all the information in the database so we’re gonna start with all and then we will go into getting single items filtering that data and go to our command prompt.

Here and we’ll actually start making our queries from here to do this let’s just go ahead and run** Python manage.py shell** and I am in my project file so make sure you’re in there when you start and what this does is it gives us an interactive shell to actually start working with our data so this is a lot like the Python shell but because we did manage.py it allows us to do things a Django way and actually query our database now open up the command prompt and let’s go ahead and start making our first queries.

#django #django model queries #django orm #django queries #django query #model django query #model query #query with django

Como Integrar o Django Com os Canais Do Django

Neste tutorial, construiremos um aplicativo de bate-papo em tempo real com o Django Channels , focando em como integrar o Django com o Django Channels.

Por que outro aplicativo de bate-papo? Bem, um aplicativo de bate-papo é a maneira mais fácil de mostrar o poder dos canais. Dito isso, este tutorial vai além do básico, implementando vários tipos de solicitação, persistência de mensagem/sala de bate-papo e mensagens privadas (um para um). Depois de passar pelo tutorial, você poderá criar aplicativos em tempo real.

O que é o Django Channels?

O Django Channels (ou apenas Channels) estende os recursos internos do Django , permitindo que os projetos do Django lidem não apenas com HTTP, mas também com protocolos que exigem conexões de longa duração, como WebSockets, MQTT (IoT), chatbots, rádios e outros recursos reais. aplicações de tempo. Além disso, ele fornece suporte para vários recursos principais do Django, como autenticação e sessões.

Uma configuração básica de canais se parece com isto:

Estrutura básica do Django + Canais

Para saber mais sobre os Canais, confira o guia de introdução na documentação oficial .

Sincronização vs Assíncrona

Por causa das diferenças entre Channels e Django, teremos que alternar frequentemente entre execução de código sincronizado e assíncrono. Por exemplo, o banco de dados Django precisa ser acessado usando código síncrono, enquanto a camada de canal Canais precisa ser acessada usando código assíncrono.

A maneira mais fácil de alternar entre os dois é usando as funções internas do Django asgiref ( asgrief.sync):

  1. sync_to_async- pega uma função de sincronização e retorna uma função assíncrona que a envolve
  2. async_to_sync- pega uma função assíncrona e retorna uma função de sincronização

Não se preocupe com isso ainda, vamos mostrar um exemplo prático mais adiante no tutorial.

Configuração do projeto

Novamente, estaremos construindo um aplicativo de bate-papo. O aplicativo terá várias salas onde os usuários autenticados pelo Django podem conversar. Cada sala terá uma lista de usuários atualmente conectados. Também implementaremos mensagens privadas e individuais.

Configuração do projeto Django

Comece criando um novo diretório e configurando um novo projeto Django:

$ mkdir django-channels-example && cd django-channels-example
$ python3.9 -m venv env
$ source env/bin/activate

(env)$ pip install django==4.0
(env)$ django-admin startproject core .

Depois disso, crie um novo aplicativo Django chamado chat:

(env)$ python manage.py startapp chat

Registre o aplicativo em core/settings.py em INSTALLED_APPS:

# core/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'chat.apps.ChatConfig',  # new
]

Criar modelos de banco de dados

Em seguida, vamos criar dois modelos Django, Roome Message, em chat/models.py :

# chat/models.py

from django.contrib.auth.models import User
from django.db import models


class Room(models.Model):
    name = models.CharField(max_length=128)
    online = models.ManyToManyField(to=User, blank=True)

    def get_online_count(self):
        return self.online.count()

    def join(self, user):
        self.online.add(user)
        self.save()

    def leave(self, user):
        self.online.remove(user)
        self.save()

    def __str__(self):
        return f'{self.name} ({self.get_online_count()})'


class Message(models.Model):
    user = models.ForeignKey(to=User, on_delete=models.CASCADE)
    room = models.ForeignKey(to=Room, on_delete=models.CASCADE)
    content = models.CharField(max_length=512)
    timestamp = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f'{self.user.username}: {self.content} [{self.timestamp}]'

Notas:

  1. Roomrepresenta uma sala de bate-papo. Ele contém um onlinecampo para rastrear quando os usuários se conectam e se desconectam da sala de bate-papo.
  2. Messagerepresenta uma mensagem enviada para a sala de chat. Usaremos este modelo para armazenar todas as mensagens enviadas no chat.

Execute os comandos makemigrationse para sincronizar o banco de dados:migrate

(env)$ python manage.py makemigrations
(env)$ python manage.py migrate

Registre os modelos em chat/admin.py para que fiquem acessíveis no painel de administração do Django:

# chat/admin.py

from django.contrib import admin

from chat.models import Room, Message

admin.site.register(Room)
admin.site.register(Message)

Visualizações e URLs

O aplicativo da web terá os dois URLs a seguir:

  1. /chat/- seletor de sala de bate-papo
  2. /chat/<ROOM_NAME>/- sala de bate-papo

Adicione as seguintes visualizações a chat/views.py :

# chat/views.py

from django.shortcuts import render

from chat.models import Room


def index_view(request):
    return render(request, 'index.html', {
        'rooms': Room.objects.all(),
    })


def room_view(request, room_name):
    chat_room, created = Room.objects.get_or_create(name=room_name)
    return render(request, 'room.html', {
        'room': chat_room,
    })

Crie um arquivo urls.py dentro do chataplicativo:

# chat/urls.py

from django.urls import path

from . import views

urlpatterns = [
    path('', views.index_view, name='chat-index'),
    path('<str:room_name>/', views.room_view, name='chat-room'),
]

Atualize também o arquivo urls.py no nível do projeto com o chataplicativo:

# core/urls.py

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('chat/', include('chat.urls')),  # new
    path('admin/', admin.site.urls),
]

Modelos e arquivos estáticos

Crie um arquivo index.html dentro de uma nova pasta chamada "templates" em "chat":

<!-- chat/templates/index.html -->

{% load static %}

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>django-channels-chat</title>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css">
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"></script>
        <style>
            #roomSelect {
                height: 300px;
            }
        </style>
    </head>
    <body>
        <div class="container mt-3 p-5">
            <h2>django-channels-chat</h2>
            <div class="row">
                <div class="col-12 col-md-8">
                    <div class="mb-2">
                        <label for="roomInput">Enter a room name to connect to it:</label>
                        <input type="text" class="form-control" id="roomInput" placeholder="Room name">
                        <small id="roomInputHelp" class="form-text text-muted">If the room doesn't exist yet, it will be created for you.</small>
                    </div>
                    <button type="button" id="roomConnect" class="btn btn-success">Connect</button>
                </div>
                <div class="col-12 col-md-4">
                    <label for="roomSelect">Active rooms</label>
                    <select multiple class="form-control" id="roomSelect">
                        {% for room in rooms %}
                            <option>{{ room }}</option>
                        {% endfor %}
                    </select>
                </div>
            </div>
        </div>
        <script src="{% static 'index.js' %}"></script>
    </body>
</html>

Em seguida, adicione room.html dentro da mesma pasta:

<!-- chat/templates/room.html -->

{% load static %}

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>django-channels-chat</title>
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css">
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js"></script>
        <style>
            #chatLog {
                height: 300px;
                background-color: #FFFFFF;
                resize: none;
            }

            #onlineUsersSelector {
                height: 300px;
            }
        </style>
    </head>
    <body>
        <div class="container mt-3 p-5">
            <h2>django-channels-chat</h2>
            <div class="row">
                <div class="col-12 col-md-8">
                    <div class="mb-2">
                        <label for="chatLog">Room: #{{ room.name }}</label>
                        <textarea class="form-control" id="chatLog" readonly></textarea>
                    </div>
                    <div class="input-group">
                        <input type="text" class="form-control" id="chatMessageInput" placeholder="Enter your chat message">
                        <div class="input-group-append">
                            <button class="btn btn-success" id="chatMessageSend" type="button">Send</button>
                        </div>
                    </div>
                </div>
                <div class="col-12 col-md-4">
                    <label for="onlineUsers">Online users</label>
                    <select multiple class="form-control" id="onlineUsersSelector">
                    </select>
                </div>
            </div>
            {{ room.name|json_script:"roomName" }}
        </div>
        <script src="{% static 'room.js' %}"></script>
    </body>
</html>

Para tornar nosso código mais legível, incluiremos o código JavaScript em arquivos separados -- index.js e room.js , respectivamente. Como não podemos acessar o contexto do Django em JavaScript, podemos usar a tag de modelo json_script para armazená room.name-lo e buscá-lo no arquivo JavaScript.

Dentro de "chat", crie uma pasta chamada "static". Em seguida, dentro de "static", crie um arquivo index.js e um arquivo room.js.

index.js :

// chat/static/index.js

console.log("Sanity check from index.js.");

// focus 'roomInput' when user opens the page
document.querySelector("#roomInput").focus();

// submit if the user presses the enter key
document.querySelector("#roomInput").onkeyup = function(e) {
    if (e.keyCode === 13) {  // enter key
        document.querySelector("#roomConnect").click();
    }
};

// redirect to '/room/<roomInput>/'
document.querySelector("#roomConnect").onclick = function() {
    let roomName = document.querySelector("#roomInput").value;
    window.location.pathname = "chat/" + roomName + "/";
}

// redirect to '/room/<roomSelect>/'
document.querySelector("#roomSelect").onchange = function() {
    let roomName = document.querySelector("#roomSelect").value.split(" (")[0];
    window.location.pathname = "chat/" + roomName + "/";
}

sala.js :

// chat/static/room.js

console.log("Sanity check from room.js.");

const roomName = JSON.parse(document.getElementById('roomName').textContent);

let chatLog = document.querySelector("#chatLog");
let chatMessageInput = document.querySelector("#chatMessageInput");
let chatMessageSend = document.querySelector("#chatMessageSend");
let onlineUsersSelector = document.querySelector("#onlineUsersSelector");

// adds a new option to 'onlineUsersSelector'
function onlineUsersSelectorAdd(value) {
    if (document.querySelector("option[value='" + value + "']")) return;
    let newOption = document.createElement("option");
    newOption.value = value;
    newOption.innerHTML = value;
    onlineUsersSelector.appendChild(newOption);
}

// removes an option from 'onlineUsersSelector'
function onlineUsersSelectorRemove(value) {
    let oldOption = document.querySelector("option[value='" + value + "']");
    if (oldOption !== null) oldOption.remove();
}

// focus 'chatMessageInput' when user opens the page
chatMessageInput.focus();

// submit if the user presses the enter key
chatMessageInput.onkeyup = function(e) {
    if (e.keyCode === 13) {  // enter key
        chatMessageSend.click();
    }
};

// clear the 'chatMessageInput' and forward the message
chatMessageSend.onclick = function() {
    if (chatMessageInput.value.length === 0) return;
    // TODO: forward the message to the WebSocket
    chatMessageInput.value = "";
};

Sua estrutura final de diretórios do aplicativo "chat" deve ficar assim:

chat
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│   ├── 0001_initial.py
│   ├── __init__.py
├── models.py
├── static
│   ├── index.js
│   └── room.js
├── templates
│   ├── index.html
│   └── room.html
├── tests.py
├── urls.py
└── views.py

Teste

Com a configuração básica do projeto, vamos testar as coisas no navegador.

Inicie o servidor de desenvolvimento Django:

(env)$ python manage.py runserver

Navegue até http://localhost:8000/chat/ . Você verá o seletor de sala:

Seletor de Sala dos Canais do Django

Para garantir que os arquivos estáticos estejam configurados corretamente, abra o 'Console do desenvolvedor'. Você deve ver a verificação de sanidade:

Sanity check from index.js.

Em seguida, digite algo na entrada de texto 'Nome da sala' e pressione enter. Você será redirecionado para a sala:

Seletor de Sala dos Canais do Django

Estes são apenas modelos estáticos. Implementaremos a funcionalidade para o chat e usuários online mais tarde.

Adicionar canais

Em seguida, vamos conectar os canais do Django.

Comece instalando o pacote:

(env)$ pip install channels==3.0.4

Em seguida, adicione channelsao seu INSTALLED_APPSinterior core/settings.py :

# core/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'chat.apps.ChatConfig',
    'channels',  # new
]

Como usaremos WebSockets em vez de HTTP para comunicar do cliente para o servidor, precisamos envolver nossa configuração ASGI com ProtocolTypeRouter em core/asgi.py :

# core/asgi.py

import os

from channels.routing import ProtocolTypeRouter
from django.core.asgi import get_asgi_application

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

application = ProtocolTypeRouter({
  'http': get_asgi_application(),
})

Este roteador roteará o tráfego para diferentes partes do aplicativo da Web, dependendo do protocolo usado.

As versões do Django <= 2.2 não possuem suporte ASGI embutido. Para channelsrodar com versões mais antigas do Django, consulte o guia de instalação oficial .

Em seguida, precisamos informar ao Django a localização do nosso aplicativo ASGI. Adicione o seguinte ao seu arquivo core/settings.py , logo abaixo da WSGI_APPLICATIONconfiguração:

# core/settings.py

WSGI_APPLICATION = 'core.wsgi.application'
ASGI_APPLICATION = 'core.asgi.application'  # new

Ao executar o servidor de desenvolvimento agora, você verá que os canais estão sendo usados:

Starting ASGI/Channels version 3.0.4 development server at http://127.0.0.1:8000/

Adicionar camada de canal

Uma camada de canal é um tipo de sistema de comunicação, que permite que várias partes do nosso aplicativo troquem mensagens, sem transportar todas as mensagens ou eventos pelo banco de dados.

Precisamos de uma camada de canal para dar aos consumidores (que implementaremos na próxima etapa) a capacidade de conversar uns com os outros.

Embora possamos usar a camada InMemoryChannelLayer já que estamos no modo de desenvolvimento, usaremos uma camada pronta para produção, RedisChannelLayer .

Como essa camada requer Redis , execute o seguinte comando para colocá-la em funcionamento com o Docker :

(env)$ docker run -p 6379:6379 -d redis:5

Este comando baixa a imagem e ativa um contêiner Redis Docker na porta 6379.

Se você não quiser usar o Docker, sinta-se à vontade para baixar o Redis diretamente do site oficial .

Para se conectar ao Redis a partir do Django, precisamos instalar um pacote adicional chamado channels_redis :

(env)$ pip install channels_redis==3.3.1

Depois disso, configure a camada em core/settings.py assim:

# core/settings.py

CHANNEL_LAYERS = {
    'default': {
        'BACKEND': 'channels_redis.core.RedisChannelLayer',
        'CONFIG': {
            "hosts": [('127.0.0.1', 6379)],
        },
    },
}

Aqui, informamos a channels_redis onde o servidor Redis está localizado.

Para testar se tudo funciona como esperado, abra o shell do Django:

(env)$ python manage.py shell

Então corra:

>>> import channels.layers
>>> channel_layer = channels.layers.get_channel_layer()
>>>
>>> from asgiref.sync import async_to_sync
>>> async_to_sync(channel_layer.send)('test_channel', {'type': 'hello'})
>>> async_to_sync(channel_layer.receive)('test_channel')
{'type': 'hello'}

Aqui, nos conectamos à camada de canal usando as configurações definidas em core/settings.py . Em seguida, costumávamos channel_layer.sendenviar uma mensagem ao test_channelgrupo e channel_layer.receiveler todas as mensagens enviadas ao mesmo grupo.

Observe que agrupamos todas as chamadas de função async_to_syncporque a camada de canal é assíncrona.

Enter quit()para sair do shell.

Adicionar consumidor de canais

Um consumidor é a unidade básica do código de Canais. Eles são pequenos aplicativos ASGI, dirigidos por eventos. Eles são semelhantes às visualizações do Django. No entanto, ao contrário das visualizações do Django, os consumidores são de longa duração por padrão. Um projeto Django pode ter vários consumidores que são combinados usando roteamento de canais (que veremos na próxima seção).

Cada consumidor tem seu próprio escopo, que é um conjunto de detalhes sobre uma única conexão de entrada. Eles contêm dados como tipo de protocolo, caminho, cabeçalhos, argumentos de roteamento, agente do usuário e muito mais.

Crie um novo arquivo chamado consumer.py dentro de "chat":

# chat/consumers.py

import json

from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer

from .models import Room


class ChatConsumer(WebsocketConsumer):

    def __init__(self, *args, **kwargs):
        super().__init__(args, kwargs)
        self.room_name = None
        self.room_group_name = None
        self.room = None

    def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = f'chat_{self.room_name}'
        self.room = Room.objects.get(name=self.room_name)

        # connection has to be accepted
        self.accept()

        # join the room group
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name,
        )

    def disconnect(self, close_code):
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name,
        )

    def receive(self, text_data=None, bytes_data=None):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        # send chat message event to the room
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'chat_message',
                'message': message,
            }
        )

    def chat_message(self, event):
        self.send(text_data=json.dumps(event))

Aqui, criamos um ChatConsumer, que herda de WebsocketConsumer . WebsocketConsumerfornece três métodos, connect(), disconnect()e receive():

  1. No interior connect()ligamos accept()para aceitar a conexão. Depois disso, adicionamos o usuário ao grupo de camadas do canal.
  2. Dentro disconnect()nós removemos o usuário do grupo de camadas do canal.
  3. Dentro receive(), analisamos os dados para JSON e extraímos o arquivo message. Em seguida, encaminhamos o messageuso group_sendpara chat_message.

Ao usar a camada do canal group_send, seu consumidor precisa ter um método para cada mensagem JSON que typevocê usa. Na nossa situação, typeé igual a chat_message. Assim, adicionamos um método chamado chat_message.

Se você usar pontos em seus tipos de mensagem, os Canais os converterão automaticamente em sublinhados ao procurar um método - por exemplo, chat.messagese tornará chat_message.

Como WebsocketConsumeré um consumidor síncrono, tivemos que chamar async_to_syncao trabalhar com a camada de canal. Decidimos usar um consumidor de sincronização, já que o aplicativo de bate-papo está intimamente conectado ao Django (que é sincronizado por padrão). Em outras palavras, não obteríamos um aumento de desempenho usando um consumidor assíncrono.

Você deve usar consumidores de sincronização por padrão. Além do mais, use apenas consumidores assíncronos nos casos em que você está absolutamente certo de que está fazendo algo que se beneficiaria do tratamento assíncrono (por exemplo, tarefas de longa duração que podem ser feitas em paralelo) e você está usando apenas async-native bibliotecas.

Adicionar roteamento de canais

Channels fornece diferentes classes de roteamento que nos permitem combinar e empilhar consumidores. Eles são semelhantes aos URLs do Django.

Adicione um arquivo routing.py ao "chat":

# 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()),
]

Registre o arquivo routing.py dentro de core/asgi.py :

# core/asgi.py

import os

from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application

import chat.routing

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

application = ProtocolTypeRouter({
  'http': get_asgi_application(),
  'websocket': URLRouter(
      chat.routing.websocket_urlpatterns
    ),
})

WebSockets (front-end)

Para se comunicar com os canais do frontend, usaremos a API WebSocket .

WebSockets são extremamente fáceis de usar. Primeiro, você precisa estabelecer uma conexão fornecendo um urle, em seguida, poderá ouvir os seguintes eventos:

  1. onopen- chamado quando uma conexão WebSocket é estabelecida
  2. onclose- chamado quando uma conexão WebSocket é destruída
  3. onmessage- chamado quando um WebSocket recebe uma mensagem
  4. onerror- chamado quando um WebSocket encontra um erro

Para integrar WebSockets ao aplicativo, adicione o seguinte à parte inferior de room.js :

// chat/static/room.js

let chatSocket = null;

function connect() {
    chatSocket = new WebSocket("ws://" + window.location.host + "/ws/chat/" + roomName + "/");

    chatSocket.onopen = function(e) {
        console.log("Successfully connected to the WebSocket.");
    }

    chatSocket.onclose = function(e) {
        console.log("WebSocket connection closed unexpectedly. Trying to reconnect in 2s...");
        setTimeout(function() {
            console.log("Reconnecting...");
            connect();
        }, 2000);
    };

    chatSocket.onmessage = function(e) {
        const data = JSON.parse(e.data);
        console.log(data);

        switch (data.type) {
            case "chat_message":
                chatLog.value += data.message + "\n";
                break;
            default:
                console.error("Unknown message type!");
                break;
        }

        // scroll 'chatLog' to the bottom
        chatLog.scrollTop = chatLog.scrollHeight;
    };

    chatSocket.onerror = function(err) {
        console.log("WebSocket encountered an error: " + err.message);
        console.log("Closing the socket.");
        chatSocket.close();
    }
}
connect();

Após estabelecer a conexão WebSocket, no onmessagecaso, determinamos o tipo de mensagem com base em data.type. Observe como envolvemos o WebSocket dentro do connect()método para ter a capacidade de restabelecer a conexão caso ela caia.

Por fim, altere o TODO interno chatMessageSend.onclickFormpara o seguinte:

// chat/static/room.js

chatSocket.send(JSON.stringify({
    "message": chatMessageInput.value,
}));

O manipulador completo agora deve ficar assim:

// chat/static/room.js

chatMessageSend.onclick = function() {
    if (chatMessageInput.value.length === 0) return;
    chatSocket.send(JSON.stringify({
        "message": chatMessageInput.value,
    }));
    chatMessageInput.value = "";
};

A primeira versão do chat está pronta.

Para testar, execute o servidor de desenvolvimento. Em seguida, abra duas janelas de navegador privadas/anônimas e, em cada uma, navegue até http://localhost:8000/chat/default/ . Você deve ser capaz de enviar uma mensagem:

Teste de canais do Django

Isso é tudo para a funcionalidade básica. Em seguida, veremos a autenticação.

Autenticação

Processo interno

Channels vem com uma classe embutida para sessão Django e gerenciamento de autenticação chamada AuthMiddlewareStack.

Para usá-lo, a única coisa que precisamos fazer é envolver URLRouterdentro do core/asgi.py assim:

# core/asgi.py

import os

from channels.auth import AuthMiddlewareStack  # new import
from channels.routing import ProtocolTypeRouter, URLRouter
from django.core.asgi import get_asgi_application

import chat.routing

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

application = ProtocolTypeRouter({
  'http': get_asgi_application(),
  'websocket': AuthMiddlewareStack(  # new
        URLRouter(
            chat.routing.websocket_urlpatterns
        )
    ),  # new
})

Agora, sempre que um cliente autenticado ingressar, o objeto de usuário será adicionado ao escopo. Ele pode ser acessado assim:

user = self.scope['user']

Se você deseja executar Canais com uma estrutura JavaScript de front-end (como Angular, React ou Vue), precisará usar um sistema de autenticação diferente (por exemplo, autenticação de token). Se você quiser aprender a usar a autenticação de token com os Canais, confira os seguintes cursos:

  1. Desenvolvendo um aplicativo de táxi em tempo real com canais Django e Angular
  2. Desenvolvendo um aplicativo de táxi em tempo real com Django Channels e React

Vamos modificar o ChatConsumerpara bloquear usuários não autenticados de falar e para exibir o nome de usuário do usuário com a mensagem.

Altere chat/consumers.py para o seguinte:

# chat/consumers.py

import json

from asgiref.sync import async_to_sync
from channels.generic.websocket import WebsocketConsumer

from .models import Room, Message  # new import


class ChatConsumer(WebsocketConsumer):

    def __init__(self, *args, **kwargs):
        super().__init__(args, kwargs)
        self.room_name = None
        self.room_group_name = None
        self.room = None
        self.user = None  # new

    def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_name']
        self.room_group_name = f'chat_{self.room_name}'
        self.room = Room.objects.get(name=self.room_name)
        self.user = self.scope['user']  # new

        # connection has to be accepted
        self.accept()

        # join the room group
        async_to_sync(self.channel_layer.group_add)(
            self.room_group_name,
            self.channel_name,
        )

    def disconnect(self, close_code):
        async_to_sync(self.channel_layer.group_discard)(
            self.room_group_name,
            self.channel_name,
        )

    def receive(self, text_data=None, bytes_data=None):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        if not self.user.is_authenticated:  # new
            return                          # new

        # send chat message event to the room
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'chat_message',
                'user': self.user.username,  # new
                'message': message,
            }
        )
        Message.objects.create(user=self.user, room=self.room, content=message)  # new

    def chat_message(self, event):
        self.send(text_data=json.dumps(event))

A parte dianteira

Em seguida, vamos modificar room.js para exibir o nome de usuário do usuário. Dentro chatSocket.onMessagede , adicione o seguinte:

// chat/static/room.js

chatSocket.onmessage = function(e) {
    const data = JSON.parse(e.data);
    console.log(data);

    switch (data.type) {
        case "chat_message":
            chatLog.value += data.user + ": " + data.message + "\n";  // new
            break;
        default:
            console.error("Unknown message type!");
            break;
    }

    // scroll 'chatLog' to the bottom
    chatLog.scrollTop = chatLog.scrollHeight;
};

Teste

Crie um superusuário, que você usará para testar:

(env)$ python manage.py createsuperuser

Execute o servidor:

(env)$ python manage.py runserver

Abra o navegador e faça login usando o login de administrador do Django em http://localhost:8000/admin .

Em seguida, navegue até http://localhost:8000/chat/default . Teste!

Canais do Django Bate-papo com Nomes de Usuário

Saia do administrador do Django. Navegue até http://localhost:8000/chat/default . O que acontece quando você tenta postar uma mensagem?

Mensagens do usuário

Em seguida, adicionaremos os três tipos de mensagem a seguir:

  1. user_list- enviado para o usuário recém-ingressado ( data.users= lista de usuários online)
  2. user_join- enviado quando um usuário entra em uma sala de bate-papo
  3. user_leave- enviado quando um usuário sai de uma sala de bate-papo

Processo interno

No final do connectmétodo, ChatConsumeradicione:

# chat/consumers.py

def connect(self):
    # ...

    # send the user list to the newly joined user
    self.send(json.dumps({
        'type': 'user_list',
        'users': [user.username for user in self.room.online.all()],
    }))

    if self.user.is_authenticated:
        # send the join event to the room
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'user_join',
                'user': self.user.username,
            }
        )
        self.room.online.add(self.user)

No final do disconnectmétodo, ChatConsumeradicione:

# chat/consumers.py

def disconnect(self, close_code):
    # ...

    if self.user.is_authenticated:
        # send the leave event to the room
        async_to_sync(self.channel_layer.group_send)(
            self.room_group_name,
            {
                'type': 'user_leave',
                'user': self.user.username,
            }
        )
        self.room.online.remove(self.user)

Como adicionamos novos tipos de mensagem, também precisamos adicionar os métodos para a camada de canal. No final de chat/consumers.py adicione:

# chat/consumers.py

def user_join(self, event):
    self.send(text_data=json.dumps(event))

def user_leave(self, event):
    self.send(text_data=json.dumps(event))

Seu consumer.py após esta etapa deve ficar assim: consumer.py .

A parte dianteira

Para manipular as mensagens do frontend, adicione os seguintes casos à instrução switch no chatSocket.onmessagemanipulador:

// chat/static/room.js

switch (data.type) {
    // ...
    case "user_list":
        for (let i = 0; i < data.users.length; i++) {
            onlineUsersSelectorAdd(data.users[i]);
        }
        break;
    case "user_join":
        chatLog.value += data.user + " joined the room.\n";
        onlineUsersSelectorAdd(data.user);
        break;
    case "user_leave":
        chatLog.value += data.user + " left the room.\n";
        onlineUsersSelectorRemove(data.user);
        break;
    // ...

Teste

Execute o servidor novamente, faça login e visite http://localhost:8000/chat/default .

Mensagem de ingresso nos canais do Django

Agora você deve poder ver as mensagens de entrada e saída. A lista de usuários também deve ser preenchida.

Mensagens Privadas

O pacote Channels não permite filtragem direta, portanto, não há um método interno para enviar mensagens de um cliente para outro cliente. Com Canais, você pode enviar uma mensagem para:

  1. O cliente do consumidor ( self.send)
  2. Um grupo de camadas de canal ( self.channel_layer.group_send)

Assim, para implementar mensagens privadas, vamos:

  1. Crie um novo grupo chamado inbox_%USERNAME%sempre que um cliente ingressar.
  2. Adicione o cliente ao seu próprio grupo de caixa de entrada ( inbox_%USERNAME%).
  3. Remova o cliente de seu grupo de caixa de entrada ( inbox_%USERNAME%) quando ele se desconectar.

Uma vez implementado, cada cliente terá sua própria caixa de entrada para mensagens privadas. Outros clientes podem enviar mensagens privadas para inbox_%TARGET_USERNAME%.

Processo interno

Modifique chat/consumers.py .

# chat/consumers.py

class ChatConsumer(WebsocketConsumer):

    def __init__(self, *args, **kwargs):
        # ...
        self.user_inbox = None  # new

    def connect(self):
        # ...
        self.user_inbox = f'inbox_{self.user.username}'  # new

        # accept the incoming connection
        self.accept()

        # ...

        if self.user.is_authenticated:
            # -------------------- new --------------------
            # create a user inbox for private messages
            async_to_sync(self.channel_layer.group_add)(
                self.user_inbox,
                self.channel_name,
            )
            # ---------------- end of new ----------------
            # ...

    def disconnect(self, close_code):
        # ...

        if self.user.is_authenticated:
            # -------------------- new --------------------
            # delete the user inbox for private messages
            async_to_sync(self.channel_layer.group_add)(
                self.user_inbox,
                self.channel_name,
            )
            # ---------------- end of new ----------------
            # ...

Então, nós:

  1. Adicionado e inicializado user_inboxem .ChatConsumerconnect()
  2. Adicionado o usuário ao user_inboxgrupo quando ele se conecta.
  3. Removido o usuário do user_inboxgrupo quando ele se desconecta.

Em seguida, modifique receive()para lidar com mensagens privadas:

# chat/consumers.py

def receive(self, text_data=None, bytes_data=None):
    text_data_json = json.loads(text_data)
    message = text_data_json['message']

    if not self.user.is_authenticated:
        return

    # -------------------- new --------------------
    if message.startswith('/pm '):
        split = message.split(' ', 2)
        target = split[1]
        target_msg = split[2]

        # send private message to the target
        async_to_sync(self.channel_layer.group_send)(
            f'inbox_{target}',
            {
                'type': 'private_message',
                'user': self.user.username,
                'message': target_msg,
            }
        )
        # send private message delivered to the user
        self.send(json.dumps({
            'type': 'private_message_delivered',
            'target': target,
            'message': target_msg,
        }))
        return
    # ---------------- end of new ----------------

    # send chat message event to the room
    async_to_sync(self.channel_layer.group_send)(
        self.room_group_name,
        {
            'type': 'chat_message',
            'user': self.user.username,
            'message': message,
        }
    )
    Message.objects.create(user=self.user, room=self.room, content=message)

Adicione os seguintes métodos no final de chat/consumers.py :

# chat/consumers.py

def private_message(self, event):
    self.send(text_data=json.dumps(event))

def private_message_delivered(self, event):
    self.send(text_data=json.dumps(event))

Seu arquivo final chat/consumers.py deve ser igual a este: consumer.py

A parte dianteira

Para lidar com mensagens privadas no frontend, adicione private_messagee private_message_deliveredcases dentro da switch(data.type)instrução:

// chat/static/room.js

switch (data.type) {
    // ...
    case "private_message":
        chatLog.value += "PM from " + data.user + ": " + data.message + "\n";
        break;
    case "private_message_delivered":
        chatLog.value += "PM to " + data.target + ": " + data.message + "\n";
        break;
    // ...
}

Para tornar o chat um pouco mais conveniente, podemos alterar a entrada da mensagem para pm %USERNAME%quando o usuário clica em um dos usuários online no arquivo onlineUsersSelector. Adicione o seguinte manipulador à parte inferior:

// chat/static/room.js

onlineUsersSelector.onchange = function() {
    chatMessageInput.value = "/pm " + onlineUsersSelector.value + " ";
    onlineUsersSelector.value = null;
    chatMessageInput.focus();
};

Teste

É isso! O aplicativo cap agora está completo. Vamos testá-lo uma última vez.

Crie dois superusuários para teste e execute o servidor.

Abra dois navegadores privados/anônimos diferentes, fazendo login em ambos em http://localhost:8000/admin .

Em seguida, navegue até http://localhost:8000/chat/default em ambos os navegadores. Clique em um dos usuários conectados para enviar uma mensagem privada:

Versão final do bate-papo dos canais do Django

Conclusão

Neste tutorial, vimos como usar Canais com Django. Você aprendeu sobre as diferenças entre a execução de código síncrona e assíncrona junto com os conceitos dos canais a seguir:

  1. Consumidores
  2. Camadas do canal
  3. Roteamento

Por fim, juntamos tudo com o WebSockets e criamos um aplicativo de bate-papo.

Nosso bate-papo está longe de ser perfeito. Se você quiser praticar o que aprendeu, pode melhorá-lo:

  1. Adicionando salas de bate-papo somente para administradores.
  2. Enviando as últimas dez mensagens para o usuário quando ele entra em uma sala de bate-papo.
  3. Permitir que os usuários editem e excluam mensagens.
  4. Adicionando a funcionalidade '{user} está digitando'.
  5. Adicionando reações de mensagem.

As ideias são classificadas das mais fáceis para as mais difíceis de implementar.

Você pode pegar o código do repositório django-channels-example no GitHub.

Fonte:  https://testdrive.io

#django 

Ananya Gupta

Ananya Gupta

1597123834

Main Pros and Cons of Django As A Web Framework for Python Developers

Django depicts itself as “the web system for fussbudgets with cutoff times”. It was intended to help Python engineers take applications from idea to consummation as fast as could be expected under the circumstances.

It permits fast turn of events on the off chance that you need to make a CRUD application with batteries included. With Django, you won’t need to rehash an already solved problem. It just works and lets you center around your business rationale and making something clients can utilize.

Pros of Django

“Batteries included” theory

The standard behind batteries-included methods normal usefulness for building web applications accompanies the system, not as isolated libraries.

Django incorporates much usefulness you can use to deal with normal web advancement undertakings. Here are some significant level functionalities that Django gives you, which else you need to stay together if you somehow happened to utilize a small scale structure:

ORM

Database relocations

Client validation

Administrator board

Structures

Normalized structure

Django as a system proposes the right structure of an undertaking. That structure helps designers in making sense of how and where to execute any new component.

With a generally acknowledged venture structure that is like numerous tasks, it is a lot simpler to discover online good arrangements or approach the network for help. There are numerous energetic Python designers who will assist you with comprehending any issue you may experience.

Django applications

Django applications (or applications for short) permit designers to separate a task into numerous applications. An application is whatever is introduced by putting in settings.INSTALLED_APPS. This makes it simpler for engineers to add usefulness to the web application by coordinating outer Django applications into the venture.

There are many reusable modules and applications to accelerate your turn of events learn through Online Django Class and Check the Django website.

Secure of course

Django gives great security assurance out of the crate and incorporates avoidance components for basic assaults like SQL Injection (XSS) and Cross-site Request Forgery (CSRF). You can discover more subtleties in the official security diagram control.

REST structure for building APIs

Django REST Framework, commonly condensed “DRF”, is a Python library for building APIs. It has secluded and adaptable engineering that functions admirably for both straightforward and complex web APIs.

DRF gives a lot of verification and authorization strategies out of the case. It is an adaptable, full-included library with measured and adjustable engineering. It accompanies nonexclusive classes for CRUD tasks and an implicit API program for testing API endpoints.

GraphQL structure for building APIs

Huge REST APIs regularly require a lot of solicitations to various endpoints to recover every single required datum. GraphQL it’s a question language that permits us to share related information in a lot simpler design. For a prologue to GraphQL and an outline of its ideas, if it’s not too much trouble allude to the authority GraphQL documentation.

Graphene-Django gives reflections that make it simple to add GraphQL usefulness to your Django venture. Ordinary Django models, structures, validation, consent arrangements, and different functionalities can be reused to manufacture GraphQL blueprint. It additionally gives an implicit API program for testing API endpoints.

Cons of Django

Django ORM

Django ORM, made before SQLAlchemy existed, is currently much sub-par compared to SQLAlchemy. It depends on the Active Record design which is more regrettable than the Unit of Work design embraced by SQLAlchemy. This implies, in Django, models can “spare” themselves and exchanges are off as a matter of course, they are a bit of hindsight. Peruse more in Why I kind of aversion Django.

Django advances course popularity increses day by day:

Django is huge and is viewed as strong bit of programming. This permits the network to create several reusable modules and applications yet has additionally restricted the speed of advancement of the Django. On head of that Django needs to keep up in reverse similarity, so it advances gradually.

Rundown - Should I use Django as a Python designer?

While Django ORM isn’t as adaptable as SQLAlchemy and the enormous environment of reusable modules and applications hinders structure advancement - plainly Django ought to be the best option web system for Python engineers.

Elective, light systems, similar to Flask, while offering a retreat from Django huge biological system and designs, in the long haul can require substantially more additional libraries and usefulness, in the end making many experienced Python engineers winding up wishing they’d began with Django.

Django undertaking’s security and network have become enormously over the previous decade since the system’s creation. Official documentation and instructional exercises are probably the best anyplace in programming advancement. With each delivery, Django keeps on including huge new usefulness.

#django online training #django online course #online django course #django course #django training #django certification course

Marget D

Marget D

1626077187

4 key Features of Django Framework that Make it the Best Amongst all!

Django is one of the popular python based open-source web frameworks mainly used by the developers who like to have rapid development along with the clean pragmatic design.

Read this blog to know the various Django Features with details.

#django framework #django web development #django development company #django development services #python django development company #python django development