Adding extra fields to a model form in Django’s admin
I ran into this problem recently and found that the Django documentation wasn’t exactly clear on how to solve it, so I’ve provided an example in case anyone else needs to do the same thing. My goal was to add an extra form field to one of my model objects that represented a property which was not a Django model field. The catch is that Django’s ModelForm only includes Django model fields by default, so we have to overwrite it to manually handle our special fields.
If that doesn’t make sense, perhaps this example will help:
# models.py from django.contrib.gis.db import models from django.contrib.gis.geos import Point class Location(models.Model): name = models.CharField(max_length=128) # GeoDjango fields coordinate = models.PointField(null=True, blank=True) objects = models.GeoManager() # Custom latitude property def _get_latitude(self): return self.coordinates.y def _set_latitude(self, value): self.coordinate.y = value latitude = property(_get_latitude,_set_latitude) # Custom longitude property def _get_longitude(self): return self.coordinate.x def _set_longitude(self, value): self.coordinate.x = value longitude = property(_get_longitude,_set_longitude)
So I’ve got a Location object which represents some physical place in the world, and I’m using GeoDjango to store the actual GPS coordinates of the Location as a PointField. Using GeoDjango to store these coordinates lets me do some pretty neat things like geospatial queries (e.g. find all Locations within 5 miles of this coordinate). GeoDjango’s admin generators also automatically provide a nice drag and drop AJAX map that you can use to edit the Location. But it might also be convenient to be able to directly edit the latitude/longitude of the location using text inputs instead of the map, and the interface for the Location object will also be a little cleaner if I hide away the details of the PointField and simply expose the latitude and longitude as properties.
Since my custom properties are not Django fields, they will not show up in the Django admin panel. So let’s override the LocationForm to make them show up:
# admin.py from myproject.models import Location from django.contrib.gis import admin from django import forms # Custom form definition class LocationAdminForm(forms.ModelForm): # Step 1: Add the extra form fields to the ModelForm latitude = forms.FloatField(required=False) longitude = forms.FloatField(required=False) class Meta: model = Location # Step 2: Override the constructor to manually set the form's latitude and # longitude fields if a Location instance is passed into the form def __init__(self, *args, **kwargs): super(LocationAdminForm, self).__init__(*args, **kwargs) # Set the form fields based on the model object if kwargs.has_key('instance'): instance = kwargs['instance'] self.initial['latitude'] = instance.latitude self.initial['longitude'] = instance.longitude # Step 3: Override the save method to manually set the model's latitude and # longitude properties based on what was submitted from the form def save(self, commit=True): model = super(LocationAdminForm, self).save(commit=False) # Save the latitude and longitude based on the form fields model.latitude = self.cleaned_data['latitude'] model.longitude = self.cleaned_data['longitude'] if commit: model.save() return model # Custom admin definition # I'm using admin.GeoModelAdmin because I'm using GeoDjango. Usually # you would be subclassing admin.ModelAdmin. class LocationAdmin(admin.GeoModelAdmin): form = LocationAdminForm # Register admin admin.site.register(Location, LocationAdmin)
In summary, the steps to add extra fields to a ModelForm that aren’t in that model’s definition:
- Add the extra form fields to the ModelForm definition.
- Override the constructor of the ModelForm, set the self.initial properties if a model instance was passed to the form.
- Override the save method of the ModelForm, set the properties on the model instance based on the form fields.
Hope this helps!
-
AK
-
http://www.postparrot.com Matthew C. Kriner
-
Simon Gray
-
Christine Meranda
-
Steve Mulligan
-
jinsei
-
http://davidqhogan.com David Hogan
-
Derek
-
powderflask
-
powderflask
-
Filip Dupanović
-
http://www.facebook.com/mihneasim Mihnea Simian
-
http://profiles.google.com/guandalino dave guandalino
-
Ismael Solis
-
Leah Madison
-
http://www.bigstreetart.com Matt Harper
-
Leah madison
-
http://banksyart.org/banksy-prints.html Banksy Prints – The Best Prints, Posters & Shirts
-
Crc32
-
Leah Madison
-
Anonymous
-
Brian Buck
-
http://meitham.com Meitham