Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I'm trying to override the save_model method on a Django admin object to prevent a user from changing a certain field. However I can't find a way to find out if the field has changed within this method.

Here's my code so far:

def save_model(self, request, obj, form, change):     if change:          if obj.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.") 

The problem is both obj.parking_location, and form.cleaned_data['parking_location'] have the new value. (Could this be a bug in Django? It really seems like the obj should contain the pre-save values). In any case, is there another way to accomplish this?

(I'm on Django 1.2)

like image 821
Greg Avatar asked Nov 08 '11 19:11

Greg


People also ask

When saving How can you check if a field has changed Django?

Since Django 1.8 released, you can use from_db classmethod to cache old value of remote_image. Then in save method you can compare old and new value of field to check if the value has changed. @classmethod def from_db(cls, db, field_names, values): new = super(Alias, cls).

How do I override a field in Django admin?

The way to override fields is to create a Form for use with the ModelAdmin object. This didn't work for me, you need to pass an instance of the widget, rather than the class. The instance worked perfectly, though. I typically would create custom admin forms in the admin.py and not mix them in with forms.py.

What is Prepopulated_fields in Django admin?

The attribute prepopulated_fields tells the admin application to automatically fill the field slug - in this case with the text entered into the name field.

What is Admin ModelAdmin in Django?

One of the most powerful parts of Django is the automatic admin interface. It reads metadata from your models to provide a quick, model-centric interface where trusted users can manage content on your site. The admin's recommended use is limited to an organization's internal management tool.


1 Answers

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) 
like image 55
Alasdair Avatar answered Oct 04 '22 07:10

Alasdair