Using Updates API¶
Updates API provides automatic content updates, for example, when post title is changed, this change will be broadcast to all users that are currently browsing the page.
General idea¶
Updates API is exposed over WebSocket protocol at
ws://localhost/updates
. New values are broadcast to Groups named in
this fashion: [namespace]-[object id]-[path]
:
- namespace - for example, a name of model we’re updating,
- object id - pk of this object,
- path - unique identifier that describes a specific field, for example title
For 23rd user’s like status , we’d use something like:
post-1-like.23
.
To be a part of such Group, client needs to send a subscription request.
{
"subscribe": true,
"group": "post-1-like.23",
}
Where subscribe
field can be either true or false (in case client
wants to unsubscribe specific group).
Whenever field was updated with new data, server will send a message that looks like this:
{
"type": "update_value",
"path": "post-1-like.23",
"value": "1"
}
type
- type of change Server asks client to apply. Available types are:update_value
- value (ex. innerHTML of an Element containing this field) should be updated tovalue
toggle_class
- class (ex.hidden
of an Element corresponding to this field) defined inclass
field should be either added or removed to an Elementupdate_attribute
- attribute (ex.data-liked
of an Element corresponding to this field) namedattribute_name
should be changed tovalue
path
- group name (field name)value
- new value
Optional parameters:
class
- name of class to toggle (only intoggle_class
)attribute_name
- name of attribute, which value will be changed
Usage (Django)¶
Template¶
There is also a template tag available at update_tags
called
updatable
.
Usage:
{% updatable post "content" %}
This tag will include <span>
element with all required data
attributes to enable automatic updates using UpdateListener
.
You can also add safe=True
as argument if you want string to be marked as safe.
Model¶
General idea is, that if you already use serialization features from Decadence in your model, you will usually send out a few “update_value” requests during save(). To avoid reimplementing this from scratch for each model and simplify integration, push_update method is provided.
To avoid updating certain fields (upload date for blog post?), you can add this field in model:
updates_excluded = []
Fields from this list will never get checked for changes and won’t trigger any errors.
By default, each change will result in update_value
request being
broadcast. In case you want to override this behaviour, you can define a
list of options with which update()
method will be called for
specific field. A common case could be, for example, updating an URL to
image if it changed. You can either define it as a list, or a method
which returns it.
# as method, in case you need to override default value or something, in this case field is called "is_hidden"
def updates_is_hidden(self):
return [{
"type_name": "toggle_class", # use toggle_class instead of
"field": "main-div", # in case you want to override path
"classname": "hidden",
"value": not self.is_hidden, # override value, optional
}, ]
# as list, in this case field is called "image"
updates_image = [{
"type_name": "update_attribute",
"attribute_name": "src",
}, ]
One final step is overriding save()
method, capturing data before
save()
and calling push_update()
with captured data as an
argument.
def save(self, *args, **kwargs):
original_data = None
if self.pk:
old = ExampleModel.objects.get(pk=self.pk)
original_data = old.serialize()
super(ExampleModel, self).save(*args, **kwargs)
self.push_update(original_data)
Low-level¶
To send out updates, you need to either override save()
method on a
model or use signals.
Example:
from django_decadence import update
...
update(type_name="update_value", path="post-1-like.23", value="1");
...
Usage (TypeScript)¶
To simplify the process of subscribing to specific fields, there is a client for Updates API available globally under window.UpdateListener.
UpdateListener
automatically captures all elements in document
that have data-update-group
attribute containing a valid Group name.
For dynamically created Elements, you need to call UpdateListener again:
window["UpdateListener"].init(element)
. Decadence does this
automatically.