Add a websocket client to Django (not a server)

I’ve seen a bunch of stuff of how to use ASGI/Channels to add the capability to serve websocket connections to Django.

My problem is that I don’t want to serve websocket connections but I want my django application to connect to a websocket on startup and receive events from there. How would I go about doing that? I’m already running Django as ASGI because I had gathered that that might be helpful for this (which it does not seem to be really?).

I don’t see how to use Channels because that relies on a connect coming in to create a scope. In my case there won’t be an incoming scope, the app itself needs to connect out.

I’ve looked at the django-channels-irc app which seems to connect to IRC itself, but the code for that is all over the place and I’m hoping it doesn’t have to be that complicated.

Any straight-forward way to do this? Do I need to hack something together with asyncio?

An ASGI deployment doesn’t help you here indeed. It’s a definition for being a websocket server, not a client.

I’d write a management command that uses asyncio.run in its handle() to connect to the websocket. The websockets library may be of use.

ORM operations to save data to your DB should be done in a sync function wrapped with sync_to_async, and you’ll need to take care that you close database connections appropriately.

But with a separate management command, it would need to be run as a separate process (with upstart or something), right?

No way to integrate it into the Django server process because that is fundamentally request/response, scope based?

But Channels should be able to do this I guess, but I haven’t found a clear way yet.

Exactly

Any way you somehow integrate this into Django’s server process (a thread, multiprocessing) will effectively be the same as running another process. You’re better off with a separate process anyway since you can run copy of it and avoid coupling it to web requests in any way.

1 Like

And packing that in a management command would allow me to access all the other django stuff and database?

Not sure what you mean about “all the other django stuff”, but yes, a management command has full access to the models in your project.

I had to do this a couple years ago for a project. We used one of the websocket client libraries on PyPI, I don’t remember which one. But it worked well for what we needed it to do.

Ken

I’d need to access the same logic I have in my Django project based on events from the websocket (my other integrations use web hooks so they are nowhere near as annoying as this) and then do read/write on the database using my Django models.

Yes, your other modules and all other Django facilities are available. (Remember, all the commands you run under manage.py are management commands - runserver, makemigrations, shell, etc. Anything any of those commands do, you can do in your own management command.)

@alper, are third party services an available option to you? At my job, we use websockets by integrating with Pusher. If you’re able to consider a make vs. buy tradeoff, then it may be quicker/easier to get websockets going with your Django project rather than implementing it yourself.

I totally understand if that’s not an option financially, but I thought I’d bring it up as an alternative way of getting websocket functionality to work with Django.

Pusher free would do the trick for now but looking at their site, they don’t have client libraries for Python. I guess what I’m trying to do is really weird or something.

@alper Did you find the way to do that ?. I’m looking for how to doing something similar that you describe and I neither haven’t found some useful information.

I have used the management command option and I’m running it in a separate process.

Is it possible to face a brief example, how you build that up? I’m facing the exact same problem currently. I want to use django, to connect to a websocket server, send a message to it and process the received message in django.

See the docs on Writing custom django-admin commands. You have, as examples, every manage.py command supplied with Django.

Write your code for the process you describe, and use that as your handle method in your command.

You’re not going to be “using Django” to connect to the websocket server - you’re using some other library to make the connection and received messages. You’re only using Django to have access to the ORM for storing the data received as the response.

1 Like

If you have flexibility in choosing what websockets server you can use, then you could use something like this: