Custom Validation on a GeoModelAdmin's AdminForm

41 views
Skip to first unread message

Haes

unread,
Dec 14, 2010, 5:52:35 AM12/14/10
to olwidget
Hi,

I am trying to do some custom validation on a
olwidget.admin.GeoModelAdmin class using a custom AdminForm (derived
from django.forms.ModelForm) as described in the Django docs [1].

Using clean_XXX() methods to do validation on a single form field
works fine, but if I try to override the clean() method to do
validation on multiple fields, the following error occurs (see the
full stack trace here [2]) as soon as I raise a
django.forms.ValidationError:

TypeError: cannot set MyGeoModel GeometryProxy with value of type:
<type 'list'>

Could you please tell me what's the preferred/correct way to do custom
validation using clean() method using a olwidget GeoModelAdmin class?

Thanks for any help.

Cheers,

Haes.


PS: using olwidget v0.3

[1] http://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other
[2] http://pastebin.com/cD3WD7V1

Charlie DeTar

unread,
Dec 14, 2010, 8:12:28 AM12/14/10
to olwi...@googlegroups.com
Are you sure your "clean" method isn't setting a list type to the
geometry field? I just tested with the following code, using olwidget
v0.3 (working with the "testproject" project that is in olwidget):

class MyGeoAdminForm(forms.ModelForm):
class Meta:
model = GeoModel

def clean(self):
return self.cleaned_data

class MyGeoAdmin(GeoModelAdmin):
form = MyGeoAdminForm
options = {
'layers': ['google.streets', 'osm.osmarender', 'yahoo.map'],
'overlay_style': {
'fill_color': '#ffff00',
'fill_opacity': 0.7,
'stroke_width': 5,
},
'default_lon': -72,
'default_lat': 44,
'hide_textarea': False,
}
map_fields = ['point']

admin.site.register(GeoModel, MyGeoAdmin)

Everything seemed to work as expected. If you send your code for the
AdminForm and GeoModelAdmin implementations perhaps I can help more.

best,
Charlie

Haes

unread,
Dec 14, 2010, 9:43:51 AM12/14/10
to olwidget
Sorry for being unclear, the error only occurs when raising a
ValidationError within the clean() method. I just tested it with your
"testproject" as well with the same result.
> > [1]http://docs.djangoproject.com/en/dev/ref/forms/validation/#cleaning-a...
> > [2]http://pastebin.com/cD3WD7V1

Charlie DeTar

unread,
Dec 14, 2010, 10:04:43 AM12/14/10
to olwi...@googlegroups.com
Can you send your form, model, and admin code? When I add "raise
forms.ValidationError('Oops')" to the clean method I wrote, I get the
expected invalid form response in the Admin interface, and not the
TypeError you described.

What version of Django are you using?

best,
Charlie

Haes

unread,
Dec 14, 2010, 10:47:17 AM12/14/10
to olwidget
Sorry for the confusion, I really don't want to waste your time. Now
the info should be accurate.

Only v0.4 (master branch) is affected by this problem (I somehow
managed to update my dev virtualenv to v0.4 without knowing ;))

Add:

def clean(self):
raise forms.ValidationError("Test Validation Error")
return self.cleaned_data

to your 'TestAdminForm' class in your 'testolwidget' app and edit a
Country model and you should see this error. I can also confirm that
v0.3 is not affected by this.

Cheers,

Haes.

PS: I am using Django 1.2.3

Charlie DeTar

unread,
Dec 14, 2010, 10:56:32 AM12/14/10
to olwi...@googlegroups.com
On 12/14/2010 10:47 AM, Haes wrote:
> Sorry for the confusion, I really don't want to waste your time. Now
> the info should be accurate.
>
> Only v0.4 (master branch) is affected by this problem (I somehow
> managed to update my dev virtualenv to v0.4 without knowing ;))

Ah, now we're getting there, I can reproduce the error. Yep, looks like
an olwidget bug. I'm looking into it and will try to get a fix out soon.

It appears to be related to some of the magic that a "MapField" does in
v0.4 to allow multiple fields on a single map.

-charlie

Charlie DeTar

unread,
Dec 14, 2010, 12:11:28 PM12/14/10
to olwidget
OK, here's what I can gather after digging into this. This isn't so
much a bug in olwidget as a bug in the example. It's an
implementation fluke of the underlying geometry field implementation
that the ModelForm works at all in this case when there *isn't* a
ValidationError. It ought to be necessary for this to work properly
in this case that one override the clean method to alter the contents
of form.cleaned_data.

This example uses a 'MapField' type for 'boundary'. MapField is a
multi-value field -- and in the case of this example, the values
consist of one "EditableLayerField" and one "InfoLayerField" (which is
an extra field that isn't present on the model). Thus, as expected,
the value that goes into 'self.cleaned_data' is a list, with the
geometry from the EditableLayerField, and an empty string for the
InfoLayerField. Thus, a custom "clean" method should be needed to
unpack this field, e.g.:


def clean(self):
self.cleaned_data['boundary'] = self.cleaned_data['boundary']
[0]
...

An alternative, if you don't need to use extra layers in your field,
would be to use a single-value EditableMap widget instead of the multi-
value MapField. The EditableMap widget cleans by default to the right
value.

from olwidget.widgets import EditableMap

class TestAdminForm(forms.ModelForm):
boundary = forms.CharField(widget=EditableMap({'name': 'boundary',
'geometry': 'polygon', 'is_collection': True}, template="olwidget/
admin_olwidget.html"))
def clean(self):
... your implementation here ...
return self.cleaned_data

class Meta:
model = Country

The reason the TypeError was cropping up is that Django is trying to
set the list value from the multiple-value MapField back to a single
geometry in a model instance, which doesn't work. When no
ValidationError occurs, the geographic field's "get_prep_value" method
is called before saving, which unpacks the list and takes the first
element. This would be incorrect and have unexpected results with a
MapField in the usual use-case where the layers represent more than
one model field, or if the first layer isn't the one you happen to
want for that field. But since in this example the field is being
redefined to have more than one value, it's expected to have to
explicitly pick the correct value.

The olwidget MapModelForm implementation handles all of this stuff
more gracefully, but because of the noodly class structures and magic
that goes into the construction of Admin forms, metaclass inheritance
problems crop up if you try to use that instead of a subclass of
forms.ModelForm.

Hope this helps,
Charlie

Haes

unread,
Dec 15, 2010, 10:46:45 AM12/15/10
to olwidget
Hi Charlie,

thanks for the detailed answer, now it now much clearer to me how the
different layers work in v0.4. The original error on my side was easy
to fix.

OT: I added an Issue [1] for a bug that I discovered some time ago,
including a simple patch. It would be great if you could take a look
at it. This is the last issue which is holding me back to revert to
your "official" version of olwidget.

Thanks for your help so far.


[1] https://github.com/yourcelf/olwidget/issues/issue/42
Reply all
Reply to author
Forward
0 new messages