[Django]-Django Admin – save_model method – How to detect if a field has changed?

70πŸ‘

βœ…

Firstly, this isn’t a bug, it’s the documented behaviour in Django 1.2 onwards.

From the Django 1.2 release notes:

the first time you call ModelForm.is_valid(), access ModelForm.errors or otherwise trigger form validation, your model will be cleaned in-place. This conversion used to happen when the model was saved. If you need an unmodified instance of your model, you should pass a copy to the ModelForm constructor.

If you want to prevent the user from editing a paticular field, a better approach might be to use the ModelAdmin.readonly_fields option.

class VehicleRegistrationAdmin(admin.ModelAdmin):
    readonly_fields = ('parking_location',)

Or, you could replace the ModelAdmin.form with a custom form that excludes that field.

class VehicleRegistrationForm(forms.ModelForm):
    class Meta:
        exclude = ('parking_location',)

class VehicleRegistrationAdmin(admin.ModelAdmin):
    form = VehicleRegistrationForm

Finally, to answer your question more directly, you can check whether a field has changed in the save_model method by inspecting form.changed_data. This is a list of the names of the fields which have changed.

def save_model(self, request, obj, form, change):
    if 'parking_location' in form.changed_data:
        messages.info(request, "Parking location has changed")
    else:
        messages.info(request, "Parking location has not changed")
    super(MyVehiclesAdmin, self).save_model(request, obj, form, change)
πŸ‘€Alasdair

43πŸ‘

For those wondering about the change parameter:

This parameter will be True if this is a change on an existing model, it is False if the model is a newly created instance.

To check whether any fields have been changed: form.changed_data will contain the changed fields which means that it is empty if there are no changes.

πŸ‘€Risadinha

8πŸ‘

Ok, I found a work-around. This still seems like a bug to me though.

def save_model(self, request, obj, form, change):
    if change: 
        vr = VehicleRegistration.objects.get(pk=obj.id)
        if vr.parking_location == form.cleaned_data['parking_location']:
            super(MyVehiclesAdmin, self).save_model(request, obj, form, change)
        else:
            messages.error(request, 
                "The Parking Location field cannot be changed.")
πŸ‘€Greg

3πŸ‘

you can always find the value from the db with MyVehicles.objects.get(pk=obj.pk)

πŸ‘€second

Leave a comment