Package: graphene-django-subscriptions
This package adds support to Subscription’s requests and its integration with websockets using Channels package. You can test websockets notifications with this mini web tool. It’s intuitive and simple:websocket_example_clientInstallation:For installing graphene-django-subscriptions, just run this command in your shell:pipinstall"graphene-django-subscriptions"Documentation:Extra functionalities  (Subscriptions):Subscription  (Abstract class to define subscriptions to a DjangoSerializerMutation)GraphqlAPIDemultiplexer  (Custom WebSocket consumer subclass that handles demultiplexing streams)Subscriptions:This first approach to add Graphql subscriptions support  with Channels in graphene-django, use channels-api package.1- Defining custom Subscriptions classes:You must to have defined a Serializer class for each model that you want to define a Subscription class:# app/graphql/subscriptions.pyimportgraphenefromgraphene_django_subscriptions.subscriptionimportSubscriptionfrom.serializersimportUserSerializer,GroupSerializerclassUserSubscription(Subscription):classMeta:serializer_class=UserSerializerstream='users'description='User Subscription'classGroupSubscription(Subscription):classMeta:serializer_class=GroupSerializerstream='groups'description='Group Subscription'Add the subscriptions definitions into your app’s schema:# app/graphql/schema.pyimportgraphenefrom.subscriptionsimportUserSubscription,GroupSubscriptionclassSubscriptions(graphene.ObjectType):user_subscription=UserSubscription.Field()GroupSubscription=PersonSubscription.Field()Add the app’s schema into your project root schema:# schema.pyimportgrapheneimportcustom.app.route.graphql.schemaclassRootQuery(custom.app.route.graphql.schema.Query,graphene.ObjectType):classMeta:description='The project root query definition'classRootMutation(custom.app.route.graphql.schema.Mutation,graphene.ObjectType):classMeta:description='The project root mutation definition'classRootSubscription(custom.app.route.graphql.schema.Subscriptions,graphene.ObjectType):classMeta:description='The project root subscription definition'schema=graphene.Schema(query=RootQuery,mutation=RootMutation,subscription=RootSubscription)2- Defining Channels settings and custom routing config:Note: For more information about this step see Channels documentation.You must to have defined a DjangoSerializerMutation class for each model that you want to define a Subscription class:We define app routing, as if they were app urls:# app/routing.pyfromgraphene_django_subscriptions.consumersimportGraphqlAPIDemultiplexerfromchannels.routingimportroute_classfrom.graphql.subscriptionsimportUserSubscription,GroupSubscriptionclassCustomAppDemultiplexer(GraphqlAPIDemultiplexer):consumers={'users':UserSubscription.get_binding().consumer,'groups':GroupSubscription.get_binding().consumer}app_routing=[route_class(CustomAppDemultiplexer)]Defining our project routing, like custom root project urls:# project/routing.pyfromchannelsimportincludeproject_routing=[include("custom.app.folder.routing.app_routing",path=r"^/custom_websocket_path"),]You should put into your INSTALLED_APPS the channels and channels_api modules and you must to add your project’s routing definition into the CHANNEL_LAYERS setting:# settings.py...INSTALLED_APPS=('django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.sites',...'channels','channels_api','custom_app')CHANNEL_LAYERS={"default":{"BACKEND":"asgiref.inmemory.ChannelLayer","ROUTING":"myproject.routing.project_routing",# Our project routing},}...You must add‘graphene_django_subscriptions.SubscriptionMiddleware’middleware at the end of your GRAPHENE dict config on your settings.py:# settings.py...GRAPHENE={'SCHEMA_INDENT':4,'MIDDLEWARE':[# Others middleware'graphene_django_subscriptions.SubscriptionMiddleware',]}...3- Subscription’s examples:In your WEB client you must define websocket connection to: ‘ws://host:port/custom_websocket_path’.
When the connection is established, the server return a websocket’s message like this:
{“channel_id”: “GthKdsYVrK!WxRCdJQMPi”, “connect”: “success”}, where you must store the channel_id value to later use in your graphql subscriptions request for subscribe or unsubscribe operations.The graphql’s subscription request accept five possible parameters:
1.operation: Operation to perform: subscribe or unsubscribe. (required)
2.action: Action to which you wish to subscribe: create, update, delete or all_actions. (required)
3.channelId: Identification of the connection by websocket. (required)
4.id: Object’s ID field value that you wish to subscribe to. (optional)
5.data: Model’s fields that you want to appear in the subscription notifications. (optional)subscription{userSubscription(action:UPDATE,operation:SUBSCRIBE,channelId:"GthKdsYVrK!WxRCdJQMPi",id:5,data:[ID,USERNAME,FIRST_NAME,LAST_NAME,EMAIL,IS_SUPERUSER]){okerrorstream}}In this case, the subscription request sent return a websocket message to client like this:{“action”: “update”, “operation”: “subscribe”, “ok”: true, “stream”: “users”, “error”: null}and from that moment each time than the user with id=5 get modified, you will receive a message through websocket’s connection with the following format:{"stream":"users","payload":{"action":"update","model":"auth.user","data":{"id":5,"username":"meaghan90","first_name":"Meaghan","last_name":"Ackerman","email":"meaghan@gmail.com","is_superuser":false}}}For unsubscribe you must send a graphql request like this:subscription{userSubscription(action:UPDATE,operation:UNSUBSCRIBE,channelId:"GthKdsYVrK!WxRCdJQMPi",id:5){okerrorstream}}NOTE: Each time than the graphql’s server restart, you must to reestablish the websocket connection and resend the graphql’s subscription request with the new websocket connection id.Change Log:v0.0.9:Fixed minor bugs.v0.0.6:Fixed minor bug on model_fields_enum generation when define fields in serializer class like this: fields = “__all__”This avoid malfunction with the posterior versions of graphene-django.v0.0.4:Fixed minor bug onsubscription_resolverfunction.v0.0.3:Addeddepromise_subscriptionmiddleware to allow use subscriptions on graphene-django>=2.0.Updated setup dependence to graphene-django-extras>=0.3.0.v0.0.2:1. Changed mutation_class dependence on Subscription Meta class definition to serializer_class to get better
integration.
2. Fixed some minor bugs.v0.0.1:First commit