mirror of
https://github.com/django/daphne.git
synced 2025-04-21 01:02:06 +03:00
Docs updates
This commit is contained in:
parent
5d2354c71b
commit
d9e8fb7032
142
docs/binding.rst
Normal file
142
docs/binding.rst
Normal file
|
@ -0,0 +1,142 @@
|
|||
Data Binding
|
||||
============
|
||||
|
||||
The Channels data binding framework automates the process of tying Django
|
||||
models into frontend views, such as javascript-powered website UIs. It provides
|
||||
a quick and flexible way to generate messages on Groups for model changes
|
||||
and to accept messages that chanes models themselves.
|
||||
|
||||
The main target for the moment is WebSockets, but the framework is flexible
|
||||
enough to be used over any protocol.
|
||||
|
||||
What does data binding allow?
|
||||
-----------------------------
|
||||
|
||||
Data binding in Channels works two ways:
|
||||
|
||||
* Outbound, where model changes made through Django are sent out to listening
|
||||
clients. This includes creation, update and deletion of instances.
|
||||
|
||||
* Inbound, where a standardised message format allow creation, update and
|
||||
deletion of instances to be made by clients sending messages.
|
||||
|
||||
Combined, these allow a UI to be designed that automatically updates to
|
||||
reflect new values and reflects across clients. A live blog is easily done
|
||||
using data binding against the post object, for example, or an edit interface
|
||||
can show data live as it's edited by other users.
|
||||
|
||||
It has some limitations:
|
||||
|
||||
* Signals are used to power outbound binding, so if you change the values of
|
||||
a model outside of Django (or use the ``.update()`` method on a QuerySet),
|
||||
the signals are not triggered and the change will not be sent out. You
|
||||
can trigger changes yourself, but you'll need to source the events from the
|
||||
right place for your system.
|
||||
|
||||
* The built-in serializers are based on the built-in Django ones and can only
|
||||
handle certain field types; for more flexibility, you can plug in something
|
||||
like the Django REST Framework serializers.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
A single Binding subclass will handle outbound and inbound binding for a model,
|
||||
and you can have multiple bindings per model (if you want different formats
|
||||
or permission checks, for example).
|
||||
|
||||
You can inherit from the base Binding and provide all the methods needed, but
|
||||
we'll focus on the WebSocket JSON variant here, as it's the easiest thing to
|
||||
get started and likely close to what you want. Start off like this::
|
||||
|
||||
from django.db import models
|
||||
from channels.binding.websockets import WebsocketBinding
|
||||
|
||||
class IntegerValue(models.Model):
|
||||
|
||||
name = models.CharField(max_length=100, unique=True)
|
||||
value = models.IntegerField(default=0)
|
||||
|
||||
class IntegerValueBinding(WebsocketBinding):
|
||||
|
||||
model = IntegerValue
|
||||
|
||||
def group_names(self, instance, action):
|
||||
return ["intval-updates"]
|
||||
|
||||
def has_permission(self, user, action, pk):
|
||||
return True
|
||||
|
||||
This defines a WebSocket binding - so it knows to send outgoing messages
|
||||
formatted as JSON WebSocket frames - and provides the two methods you must
|
||||
always provide:
|
||||
|
||||
* ``group_names`` returns a list of groups to send outbound updates to based
|
||||
on the model and action. For example, you could dispatch posts on different
|
||||
liveblogs to groups that included the parent blog ID in the name; here, we
|
||||
just use a fixed group name.
|
||||
|
||||
* ``has_permission`` returns if an inbound binding update is allowed to actually
|
||||
be carried out on the model. We've been very unsafe and made it always return
|
||||
``True``, but here is where you would check against either Django's or your
|
||||
own permission system to see if the user is allowed that action.
|
||||
|
||||
For reference, ``action`` is always one of the unicode strings ``"create"``,
|
||||
``"update"`` or ``"delete"``.
|
||||
|
||||
Just adding the binding like this in a place where it will be imported will
|
||||
get outbound messages sending, but you still need a Consumer that will both
|
||||
accept incoming binding updates and add people to the right Groups when they
|
||||
connect. For that, you need the other part of the WebSocket binding module,
|
||||
the demultiplexer::
|
||||
|
||||
from channels.binding.websockets import WebsocketBindingDemultiplexer
|
||||
from .models import IntegerValueBinding
|
||||
|
||||
class BindingConsumer(WebsocketBindingDemultiplexer):
|
||||
|
||||
bindings = [
|
||||
IntegerValueBinding,
|
||||
]
|
||||
|
||||
def connection_groups(self):
|
||||
return ["intval-updates"]
|
||||
|
||||
This class needs two things set:
|
||||
|
||||
* ``bindings``, a list of Binding subclasses (the ones from before) of the
|
||||
models you want this to receive messages for. The socket will take care of
|
||||
looking for what model the incoming message is and giving it to the correct
|
||||
Binding.
|
||||
|
||||
* ``connection_groups``, a list of groups to put people in when they connect.
|
||||
This should match the logic of ``group_names`` on your binding - we've used
|
||||
our fixed group name again.
|
||||
|
||||
Tie that into your routing and you're ready to go::
|
||||
|
||||
from channels import route_class
|
||||
from .consumers import BindingConsumer
|
||||
|
||||
channel_routing = [
|
||||
route_class(BindingConsumer, path="^binding/"),
|
||||
]
|
||||
|
||||
|
||||
Frontend Considerations
|
||||
-----------------------
|
||||
|
||||
Channels is a Python library, and so does not provide any JavaScript to tie
|
||||
the binding into your JavaScript (though hopefully some will appear over time).
|
||||
It's not very hard to write your own; messages are all in JSON format, and
|
||||
have a key of ``action`` to tell you what's happening and ``model`` with the
|
||||
Django label of the model they're on.
|
||||
|
||||
|
||||
Custom Serialization/Protocols
|
||||
------------------------------
|
||||
|
||||
Rather than inheriting from the ``WebsocketBinding``, you can inherit directly
|
||||
from the base ``Binding`` class and implement serialization and deserialization
|
||||
yourself. Until proper reference documentation for this is written, we
|
||||
recommend looking at the source code in ``channels/bindings/base.py``; it's
|
||||
reasonably well-commented.
|
|
@ -60,7 +60,7 @@ Here's what that looks like::
|
|||
"ROUTING": "myproject.routing.channel_routing",
|
||||
},
|
||||
}
|
||||
..
|
||||
|
||||
::
|
||||
|
||||
# In routing.py
|
||||
|
|
|
@ -31,6 +31,7 @@ Contents:
|
|||
deploying
|
||||
generics
|
||||
routing
|
||||
binding
|
||||
backends
|
||||
testing
|
||||
cross-compat
|
||||
|
|
Loading…
Reference in New Issue
Block a user