I have an Occurrence
model that I am putting as TabularInline
on the admin page of another model. It has a PointField
and a PolygonField
, of which at least one must exist.
Here is part of the model:
class Occurrence(models.Model):
name = models.CharField(max_length=254)
location = models.PointField(null=True, blank=True)
bounding_polygon = models.PolygonField(null=True, blank=True)
def clean(self):
# Checks if at least one of the spatial fields is filled in
if not self.location and not self.bounding_polygon:
raise ValidationError('At least one of the spatial fields (point or polygon) is required.')
In the TabularInline
I wanted to put the name
and location
but when I add new rows the map of the location
does not appear. To get around this problem, I used a form where you can enter the latitude and longitude, which is then converted to the Point
of location
.
Here is my form:
class OccurrenceForm(forms.ModelForm):
latitude = forms.FloatField(
min_value=-90,
max_value=90,
required=False,
help_text="Enter coordinates as an alternative to selecting a point on the map."
)
longitude = forms.FloatField(
min_value=-180,
max_value=180,
required=False,
)
class Meta(object):
model = Occurrence
exclude = []
def __init__(self, *args, **kwargs):
super(OccurrenceForm, self).__init__(*args, **kwargs)
coordinates = self.initial.get("location", None)
if isinstance(coordinates, Point):
self.initial["longitude"], self.initial["latitude"] = coordinates.tuple
def clean(self):
data = super(OccurrenceForm, self).clean()
#if "latitude" in self.changed_data or "longitude" in self.changed_data:
lat, lng = data.pop("latitude", None), data.pop("longitude", None)
if lat and lng:
data["location"] = Point(lng, lat, srid=4326)
return data
Here is my TabularInline model:
class OccurrencesInline(admin.TabularInline):
model = Occurrence
fields = ('name', 'latitude', 'longitude')
show_change_link = True
extra = 1
form = OccurrenceForm
However, the Point
created for the location
in the ModelForm
is not passed to the Model
clean
.
I have tested this same ModelForm
without being in a TabularInline
and it works without problems.
Does anyone have any idea why this happens?
I will post the solution, since it might be useful for someone.
The problem was that I did not put the PointField
that I have defined in the model into the fields
defined in OccurrencesInline
.
The solution was to add the field, but as I didn't want it visible I hid it using forms.HiddenInput
.
class OccurrencesInline(admin.TabularInline):
model = Occurrence
fields = ('name', 'latitude', 'longitude', 'location')
show_change_link = True
extra = 1
formset = AtLeastOneFormSet
form = OccurrenceForm
formfield_overrides = {
models.PointField: {'widget': forms.HiddenInput()},
}