Update concepts doc to not use decorators

This commit is contained in:
Andrew Godwin 2015-09-08 16:03:33 -05:00
parent c6527bebf1
commit d4c7f2db20

View File

@ -60,21 +60,25 @@ How do we use channels?
-----------------------
That's what a channel is, but how is Django using them? Well, inside Django
you can connect a function to consume a channel, like so::
you can write a function to consume a channel, like so::
from channels.decorators import consumer
@consumer("channel-name")
def my_consumer(something, **kwargs):
def my_consumer(message):
pass
And then assign a channel to it like this in the channel backend settings::
"ROUTING": {
"some-channel": "myapp.consumers.my_consumer",
}
This means that for every message on the channel, Django will call that
consumer function with the message as keyword arguments (messages are always
a dict, and are mapped to keyword arguments for send/receive).
consumer function with a message object (message objects have a "content"
attribute which is always a dict of data, and a "channel" attribute which
is the channel it came from, as well as some others).
Django can do this as rather than run in a request-response mode, Channels
changes Django so that it runs in a worker mode - it listens on all channels
that have consumers declared, and when a message arrives on one, runs the
that have consumers assigned, and when a message arrives on one, runs the
relevant consumer.
In fact, this is illustrative of the new way Django runs to enable Channels to
@ -103,10 +107,10 @@ and a channel per client for responses (e.g. ``django.wsgi.response.o4F2h2Fd``),
with the response channel a property (``reply_channel``) of the request message.
Suddenly, a view is merely another example of a consumer::
@consumer("django.wsgi.request")
def my_consumer(reply_channel, **request_data):
# Listens on django.wsgi.request.
def my_consumer(message):
# Decode the request from JSON-compat to a full object
django_request = Request.decode(request_data)
django_request = Request.decode(message.content)
# Run view
django_response = view(django_request)
# Encode the response into JSON-compat format
@ -171,7 +175,6 @@ Say I had a live blog where I wanted to push out updates whenever a new post is
saved, I would register a handler for the ``post_save`` signal and keep a
set of channels (here, using Redis) to send updates to::
redis_conn = redis.Redis("localhost", 6379)
@receiver(post_save, sender=BlogUpdate)
@ -183,10 +186,10 @@ set of channels (here, using Redis) to send updates to::
content=instance.content,
)
@consumer("django.websocket.connect")
def ws_connect(path, reply_channel, **kwargs):
# Connected to django.websocket.connect
def ws_connect(message):
# Add to reader set
redis_conn.sadd("readers", reply_channel)
redis_conn.sadd("readers", message.reply_channel.name)
While this will work, there's a small problem - we never remove people from
the ``readers`` set when they disconnect. We could add a consumer that
@ -219,11 +222,10 @@ we don't need to; Channels has it built in, as a feature called Groups::
content=instance.content,
)
@consumer("django.websocket.connect")
@consumer("django.websocket.keepalive")
def ws_connect(path, reply_channel, **kwargs):
# Connected to django.websocket.connect and django.websocket.keepalive
def ws_connect(message):
# Add to reader group
Group("liveblog").add(reply_channel)
Group("liveblog").add(message.reply_channel)
Not only do groups have their own ``send()`` method (which backends can provide
an efficient implementation of), they also automatically manage expiry of