Django: Вызывайте очистку формы перед очисткой модели
У меня есть модель Occurrence, которую я помещаю как TabularInline на страницу администратора другой модели. У нее есть PointField и PolygonField, из которых хотя бы один должен существовать.
Вот часть модели:
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.')
В TabularInline я хотел поместить name и location, но при добавлении новых строк карта location не появляется. Чтобы обойти эту проблему, я использовал форму, в которой можно ввести широту и долготу, которые затем преобразуются в Point из location.
Вот моя форма:
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
Вот моя модель TabularInline:
class OccurrencesInline(admin.TabularInline):
model = Occurrence
fields = ('name', 'latitude', 'longitude')
show_change_link = True
extra = 1
form = OccurrenceForm
Однако функция clean модели вызывается раньше функции clean формы, что приводит к возникновению ошибки ValidationError из-за того, что координаты еще не преобразованы в Point.
Есть ли способ сначала вызвать функцию формы clean, или есть другой, более подходящий способ сделать это?
Я опубликую решение, так как оно может быть полезным для кого-то.
Проблема была в том, что я не поместил PointField, которые я определил в модели, в fields, определенные в OccurrencesInline.
Решением было добавить поле, но так как я не хотел, чтобы оно было видно, я скрыл его с помощью 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()},
}