3
\$\begingroup\$

I have project on Django wich use Django Channels. I use Django Channel for sending notifications to users who are subscribed to articles changes (adding/editing/deleting comments on article).

So I've chosen this way of realization: every group of channels is an article and when changes happen, script sends notification to relevant groups. My code works correctly but I have some doubts if my choice of way of realization is most appropriate for this task. I need advice what is the best practice in my case?

Solution:

consumers.py

from channels.generic.websocket import AsyncJsonWebsocketConsumer
from channels.db import database_sync_to_async
from project.apps.account.models import UserStatus
from .models import CommentSubscribe


class CommentNotificationConsumer(AsyncJsonWebsocketConsumer):

    async def connect(self):
        await self.accept()
        if not self.scope['user'].is_anonymous:
            groups = await database_sync_to_async(self.get_users_subscription)()
            await database_sync_to_async(self.change_user_status)(True)
            await self.add_subscriptions(groups)

    async def add_subscriptions(self, groups):
        for group in groups:
            await self.channel_layer.group_add(
                'article_{0}'.format(group.article_id),
                self.channel_name
            )

    async def receive_json(self, content, **kwargs):
        command = content.get('command', None)
        article_id = content.get('article_id', None)
        if command == 'subscribe':
            await self.subscribe(article_id)
        elif command == 'unsubscribe':
            await self.unsubscribe(article_id)
        else:
            await self.send_json({
                'error': 'unknown command'
            })

    async def disconnect(self, code):
        await database_sync_to_async(self.change_user_status)(False)

    async def send_notification(self, action):
        await self.send_json(action)

    async def subscribe(self, article_id):
        await self.channel_layer.group_add(
            'article_{0}'.format(article_id),
            self.channel_name
        )

    async def unsubscribe(self, article_id):
        await self.channel_layer.group_discard(
            'article_{0}'.format(article_id),
            self.channel_name
        )

    def get_users_subscription(self):
        return CommentSubscribe.objects.filter(
            user=self.scope['user']
        )

    def change_user_status(self, online):
        return UserStatus.objects.filter(
            user=self.scope['user']
        ).update(online=online)

views.py

from .notify import send_comment_notification

class CreateComment(CreateView):

    ...

    def form_valid(self, form):
        ...
        super().form_valid(form)
        send_comment_notification('create', article_id)


class UpdateComment(UpdateView):

    ...

    def form_valid(self, form):
        ...
        super().form_valid(form)
        send_comment_notification('update', article_id)


class DeleteComment(DeleteView):

    ...

    def delete(self, request, *args, **kwargs):
        ...
        send_comment_notification('delete', article_id)

notify.py

...

def send_comment_notification(action, article_id):
    channel_layer = get_channel_layer()
    group_name = 'article_{0}'.format(article_id)
    async_to_sync(channel_layer.group_send)(
        group_name,
        {
            'type': 'send.notification',
            'data': {
                'action': action
            }
        }
    )
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.