Executando verificação de segurança...
1

"class_name" object has no attribute 'base_send'

Estou recebendo esse erro ao tentar enviar uma mensagem através da biblioteca "channels", dentro de minha aplicação em Django (python).

Meu código:

api/consumers.py

import json
from uuid import uuid4
from channels.generic.websocket import AsyncWebsocketConsumer


class NotificationConsumer(AsyncWebsocketConsumer):

    async def connect(self):
        self.room_name = str(uuid4())
        self.room_group_name = "chat_%s" % self.room_name

        await self.channel_layer.group_add(self.room_group_name, self.channel_name)
        await self.accept()


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


    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json["message"]
        
        await self.channel_layer.group_send(self.room_group_name, {"type": "chat_message", "message": message})

    
    async def chat_message(self, event):
        message = event["message"]
        await self.send(text_data=json.dumps({"message": message}))


rabbitMQ/consumer.py

import threading
import pika as rabbit
import json
from api.consumers import NotificationConsumer


class AMQPManager(threading.Thread):
    
    def callback(self, ch, method, properties, body):
        try:
            data = json.loads(body.decode())
            NotificationConsumer().send(text_data=data)

        except Exception as e:
            print('Error when sending data to websocket.')
            print(e)


    @staticmethod
    def connect():
        return rabbit.BlockingConnection(rabbit.ConnectionParameters('localhost'))

    
    def run(self):
        connection = self.connect()
        channel = connection.channel()
        
        channel.queue_declare(queue='notifications')
        print(' [*] Waiting for messages.')

        channel.basic_qos(prefetch_count=1)
        channel.basic_consume(queue='notifications', auto_ack=True, on_message_callback=self.callback)

        channel.start_consuming()

O erro acontece nessa linha, no arquivo rabbitMQ/consumer.py:
NotificationConsumer().send(text_data=data)

Error when sending data to websocket.
'NotificationConsumer' object has no attribute 'base_send'

Alguém já passou por isso ou tem alguma ideia do que pode estar errado?

Carregando publicação patrocinada...
2

Fala Pedro! Olhei a documentação aqui e não entendi uma coisa. Você chama o método .send nessa linha do erro e esse método não está definido em NotificationConsumer pelo que vi. Esse método, por acaso, é herdado de AsyncWebsocketConsumer?

1

É sim Otto! Eu herdo esse método da classe.
Mas acabei descobrindo o problema. Por algum motivo, eu naturalmente não consigo acessar alguns atributos da classe fora de seu próprio escopo. Nunca tinha visto isso antes no python. Acho que me falta algum conhecimento sobre orientação a objetos, e sobre como a declaração e acesso de atributos funciona, já que no python não existem variáveis privadas, apenas representações das mesmas.

Para corrigir o problema eu tive que importar uma função da própria biblioteca channels, e uma outra função para que pudesse utilizar métodos assíncronos dentro de um outro método que é síncrono.

from asgiref.sync import async_to_sync
from channels.layers import get_channel_layer

E depois, foi só seguir normalmente a documentação, chamando os métodos como descritos nela. Declarando qual o nome do grupo, o tipo, e a mensagem a ser enviada, consegui fazer funcionar.

data = json.loads(body.decode())
channel_layer = get_channel_layer()
async_to_sync(channel_layer.group_send)('chat_my_room', {'type': 'notification', 'message': data})
1

Perfeito Pedro! Eu não tenho muita experiência em Python também, mas aprendi POO pelo Python e este me pareceu um desses problemas de herança/instanciação a primeira vista! Fico feliz de você ter descoberto o problema e eu aqui aprendi algo a mais! Valeu!!! 😄