mirror of
https://github.com/django/daphne.git
synced 2025-07-10 16:02:18 +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",
|
"ROUTING": "myproject.routing.channel_routing",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
..
|
|
||||||
::
|
::
|
||||||
|
|
||||||
# In routing.py
|
# In routing.py
|
||||||
|
|
|
@ -31,6 +31,7 @@ Contents:
|
||||||
deploying
|
deploying
|
||||||
generics
|
generics
|
||||||
routing
|
routing
|
||||||
|
binding
|
||||||
backends
|
backends
|
||||||
testing
|
testing
|
||||||
cross-compat
|
cross-compat
|
||||||
|
|
Loading…
Reference in New Issue
Block a user