Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django-channels sending message when model changes

I'm using django-channels to organize my websockets on backend. Right now everything is working alright except of message sending to the front-end when info in db is changed. There is http endpoint to change model.

Here is my websocket consumer

import asyncio
from asgiref.sync import async_to_sync, sync_to_async
from channels.generic.websocket import AsyncJsonWebsocketConsumer
from rest_framework.response import Response
from rest_framework import status
from channels.db import database_sync_to_async

# models and serializers

from billing.models import Billing
from billing.serializers import BillingSerializer
from customers.models import Customer
from customers.serializers import CustomersSerializer
from shipping.models import Shipping
from shipping.serializers import ShippingSerializer

from .models import Order
from .serializers import OrdersSerializer
from .views import OrdersViewSet

from .exceptions import ClientError
from .utils import get_orders_or_error, get_orders_or_warning


class OrdersConsumer(AsyncJsonWebsocketConsumer):

    async def connect(self):

        orders = await get_orders_or_warning()

        if 'user' in self.scope:
            await self.close()
        else:
            await self.accept()

        self.orders = set(orders)
        # await self.create_order(content)

    async def receive_json(self, content):
        command = content.get('command', None)

        orders = await get_orders_or_warning()
        # print(list(self.orders))
        # print(set(orders))

        try:
            if command == "join":
                await self.join_room(JWT_Token=content['token'])
            elif command == "leave":
                await self.leave_room()
            elif command == "send":
                await self.send_room(content['message'])
        except ClientError as e:
            await self.send_json({"error": e.code})

    async def disconnect(self, code):
        for room_id in list(self.rooms):
            try:
                self.send_json({
                    'type': 'CLOSE',
                    'message': "Socket closed"
                })
                await self.leave_room(content['token'])
            except ClientError:
                pass

    async def join_room(self, JWT_Token):
        orders = await get_orders_or_warning()
        serializer = OrdersSerializer(orders, many=True)
        # print('serializer', serializer)

        if self.orders != set(orders):
            await self.send_json(
                {
                    'type': 'orders',
                    'data': json.dumps(serializer.data),
                },
            )

        await self.send_json(
            {
                'type': 'orders',
                'data': json.dumps(serializer.data),
            },
        )

    async def leave_room(self, JWT_Token):

        await self.channel_layer.group_send(
            orders.group_name,
            {
                'type': 'orders.leave',
                'JWT_Token': JWT_Token
            }
        )

        self.rooms.discard()

        await self.channel_layer.group_discard(
            orders.group_name,
            self.channel_name
        )

        await self.send_json({
            "leave": str(room_id),
        })

    async def send_room(self, message):
        if room_id not in self.rooms:
            raise ClientError("ROOM_ACCESS_DENIED")

        orders = await get_orders_or_warning()
        serializer = OrdersSerializer(orders, many=True)

        await self.send_json(
            {
                'type': 'orders.give',
                'data': json.dumps(serializer.data)
            }
        )
        await self.send(text_data=json.dumps({
            'message': message
        }))

    async def orders_leave(self, event):
        await self.send_json(
            {
                'type': 'LEAVE',
                'room': event["room_id"],
                'username': event["username"]
            }
        )

Here is my routing file


application = ProtocolTypeRouter({
    'websocket': (
            URLRouter([
                url('orders/', OrdersConsumer),
            ])
    )
})

I want to get all data with front-end when some changes happened. Can this be done with current consumer? And if yes, how? I've looked too many info sources i think and now I'm kinda confused how i can actually do this.

I rly don't want to rewrite the structure, if it's possible. If you can explain how and why I need to write it the way you say I will be very grateful

like image 609
Vladislav Avatar asked Oct 19 '25 01:10

Vladislav


1 Answers

You can use signals to monitor the change and send a message to the consumer using the approach defined in the docs on how to interact with the consumer from the outside

like image 90
Ken4scholars Avatar answered Oct 20 '25 15:10

Ken4scholars



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!