Google AppEngine PolyModels and ModelForms
I recently created my first PolyModel class in Google AppEngine for a new feature. The feature was pretty straight forward - allow comments for some of the entities in our application Homebook. We wanted each comment to be tied back to its target entity – a room, house, or image – in a 1-to-many (each entity can have many comments). Using PolyModel we found this to be pretty easy without duplicating a bunch of code. Essentially the structure of Comment class hierarchy looked like the following:
class Comment(PolyModel):
# bunch of common fields
class RoomComment(Comment):
target = db.ReferenceProperty(reference_class=Room, collection_name=’comments’)
class HomeComment(Comment):
target = db.ReferenceProperty(reference_class=Home, collection_name=’comments’)
class ImageComment(Comment):
target = db.ReferenceProperty(reference_class=Image, collection_name=’comments’)
Really straight forward – simple class inheritance. I then created a simple factory method that would fetch the proper class type for a given instance of one of our commentable entities. Things were moving along nicely (complete with lots of beautiful unit tests – you do write unit tests, right?) and it was time to create the add_comment view.
For the most part we use Google AppEngine’s djangoforms ModelForms, a theoretically clean and easy way to create web forms based on data models. I created my standard ModelForm class (based on our parent Comment class) and the view against which the form would post, only to be blindsided by the oddest of validation errors:
- _class
- This field is required.
Huh? _class? What gives? Well, after a couple hours of soul searching, googling (which turned up nothing), and a few tears, my genius coworker Tony Arkles had an epiphany: The PolyModel class has a _class field which is used to keep track of the PolyModel instance’s class hierarchy. We added the _class field to our form’s exclude list and the world righted itself, cats and dogs learned to coexist, and Liz Taylor finally discovered a happy marriage.
Now the question is, why is the ModelForm rendering a field that’s not a google.appengine.ext.db model property? Can anybody from Google answer me that?
on April 12, 2009 on 6:56 am
I’m out of town right now, so I can’t verify this. I’m going to guess that Google’s not the guilty party here; rather, it sounds like either a problem with the app-engine-patch/app-engine-helper/whatever you guys are using now, or a problem in the ModelForms implementation.
(On first blush, I’d say that the ModelForms implementation has no business accessing any “_private” members)