[Django Admin Customization] Avoid Overwriting Fields When Multiple Users Edit the Same Object

Problem

When two staff users open the same admin change page and perform the following actions:

  1. User A changes the name field from “test_a” to “test_b” and saves the object.
  2. User B, without refreshing the page, updates the price field from 100 to 105 (with the name field still showing “test_a”) and saves the object.

The result is that User A’s changes to the name field (“test_b”) are overwritten. The final object becomes:

  • name: “test_a”
  • price: 105

However, the expected result should be:

  • name: “test_b”
  • price: 105

Solution

To prevent this issue, I am planning to customize Django Admin’s ModelAdmin class to:

  1. On GET requests: Store the current object state in Redis.
  2. On POST requests: Use the state stored in Redis to update only the changed fields.

Below is a simplified example:

class CustomModelAdmin(ModelAdmin):
    def save_model(self, request, obj, form, change):
        if change:
            obj.save(update_fields=form.changed_data)  # Save only updated fields
        else:
            super().save_model(request, obj, form, change)

    def change_view(self, request, object_id, form_url="", extra_context=None):
        if request.method == "GET":
            obj = self.get_object(request, object_id)  # Get the current object
            if obj:
                cache_key = make_cache_key(object_id, request.user.id)  # Create a cache key
                redis_client.set(cache_key, obj)  # Store the object in Redis
        return super().change_view(request, object_id, form_url, extra_context)

    def get_object(self, request, object_id, from_field=None):
        if request.method == "POST":
            cache_key = make_cache_key(object_id, request.user.id)
            cached_data = redis_client.get(cache_key)
            if cached_data:
                return cached_data  # Return the cached object
        return super().get_object(request, object_id, from_field)

Note: make_cache_key and redis_client are assumed to be defined elsewhere.

Feedback Request

Has anyone tried a similar approach, or do you have thoughts on this idea?
I’d appreciate any feedback or suggestions for improvement.

This topic was previously discussed at Automatically setting update_fields when saving a model instance, which includes an explanation of a situation where this would not be desirable outcome.

In fact, while I do acknowledge the problem of a “lost update”, that is actually less problematic to me than inconsistent data generated as a result of an incomplete update.

A safer solution might be to ensure that only one person can edit an object at a time, or at least show a warning if it’s already being edited by someone.

I’m not saying I know how best to do this but it seems fairly common in CMS’s. e.g. I think Wagtail shows a warning, and I think WordPress shows a pop-up saying the page is already being edited, and if you want to take over.

A quick google suggests Django Concurrency might do this and it looks actively maintained.

1 Like