Artur Barseghyan (

To make a notification system for editors to avoid editing same content simultaneously.

We have one generic model multiedit.models.MultiEditLog, that holds
  • django.contrib.auth.models.User objects;
  • information about first- and last-pings of users;
  • django.contrib.contenttypes.models.ContentType object to make the app to work with ANY kind of Django objects.

See the docs of multiedit.models.MultiEditLog model and multiedit.managers.MultiEditLogManager for more information.

We never insert a new record for the group (content_type, object_id, user_id). We update the existing one. When entering an article we first try to find such a record in the list of "active" editors. If we try to update its' last_pinged value with If no records updated, we try to update just the list of editors for the given object, but unlike previous time, we update both first_pinged and last_pinged fields by setting their values to If second query does not affect any records, it means we have a fresh (first time ever) login, so we create one. By following these steps, we guarantee that we won't have garbage in the system! So, when we need to find out a new "master" (user who started editing the object first), we get the list of active users from which we select the one who had entered the live view first (fist_pinged field).

  • We have a manager for multiedit.models.MultiEditLog model to perform various operations.

    => See the multiedit.manager.MultiEditLogManager module.

  • We have a view (user "is_staff" permission requrired to enter; never cached) in order to provide ping functionality. In the admin view, we have a widget which consists of HTML/CSS/JavaScript. Our JavaScript periodically queries the "ping" view (see for more) and by that allows us to ping user.

    => See the view.

  • Next to that, we have a widget (which is very easy to use) for rendering the view (so that in our model, we would only use the existing code).

    => See the multiedit.utils.render_multiedit_widget function.

As an AJAX driven view, we will be sending an AJAX request every N seconds (configurable in settings in variable MULTIEDIT_PING_INTERVAL).

Case scenarios:

  1. Nobody has the article opened for editing and new user is entering. We check the MultiEditLog table with the following request: get all active users for the article who has been pinged as active within last 2 minutes. If nobody did that, we first:

    1. We become the master for the article.
    2. On the top of the page, where the "Currently edited by" area will be displayed, we list all other active editors (those who entered the article edit screen since we started to edit it). Beware, that in case of lost connection the rights of the "master" are regained by the user, who had entered the article next.
    3. We do show the user's status next to his name in the list above ("masters" will be clearly identified).
  2. An editor enters the edit view of the article that has already been opened by another editor. We check the MultiEditLog to get the most recent active users at all (not necessary an editor). If any found, user gets a notification (JavaScript alert), saying that the doc is already opened by another user and he is advised to leave the screen. If he does not do that anyway, we show the same widget as in previous case scenario (with users currently editing the article with roles specified).

Criteria for being a master: The active user (last pinged was made less than a minute ago minutes) for the article given who has the very first record in MultiEditLog model made for the article.

  • Install multiedit by:

    pip install -e hg+

  • Add 'multiedit' to your INSTALLED_APPS in the global

  • Override app settings in your global (see the multiedit.defaults for the list of settings). As for now, most important of those are:


  • Add the following lines to the global file.

    # MultiEdit URLs (r'^multiedit/', include('multiedit.urls')),

  • ./ syncdb # database synchronization


For making it simpler, I have made a working example of a demo. Just set the value of MULTIEDIT_SHOW_ADMIN_TEST_MODEL_DEMO to True in local_settings, restart the server and you have a working demo.

In short, you need to go through the following steps to activate the app for your model. * In your (see multiedit.models for examples, as we have tests there):

You either inherit your model from multiedit.models.MultiEditBaseModel
from multiedit.models import MultiEditBaseModel class MyTestModel(MultiEditBaseModel)
...or define a method within your model

from multiedit.models import MultiEditLog from multiedit.utils import render_multiedit_widget def multiedit_widget(self):

""" Example of multi edit widget implementation. """ return render_multiedit_widget(MultiEditLog, self)

multiedit_widget.allow_tags = True multiedit_widget.short_description = _('Active editors list')

  • In (see multiedit.admin for examples, as we have tests there):
    In the admin class of your model
    readonly_fields = ('multiedit_widget',)

Simple, isn't it? That's all.

In general, this app is well tested. See "multiedit.tests" and "" modules for examples.
Write even better docs.