kvesteri / wtforms-alchemy

Tools for creating wtforms from sqlalchemy models
Other
245 stars 59 forks source link

ModelFieldList with backref? #78

Open YKdvd opened 10 years ago

YKdvd commented 10 years ago

The docs show the example of One-to-many relations, where ModelFieldList is used to define the "locations" field for EventForm:

http://wtforms-alchemy.readthedocs.org/en/latest/relationships.html#one-to-many-relations

locations = ModelFieldList(FormField(LocationForm))

"locations" is defined in the Location model as a backref to Event, giving Event.locations. However, when I try and do something similar, I get a wtforms_alchemy.exc.InvalidAttributeException, saying Model does not contain an attribute named for my backref. The backref does exist, though.

I'll have to dig through the code or tests or examples to see if there is an actual working usage like above, but is it possible there is a glitch that is checking only for column attributes or something, and doesn't realize that ModelFieldList will be using the relationship?

YKdvd commented 10 years ago

There's a test for this (test_deep_form_relations.py), so I assume it is working. I do notice that it declares:

event = sa.orm.relationship(Event, backref='locations')

whereas I'm using the Declarative alternative of: relationship("Event", backref="locations")

If I remember, the "Event" string is turned into a callable that is evaluated at SQLA's "mapper init" time. So perhaps your "validate_attribute" method doesn't see "locations" as an attribute because SQLA hasn't mapped it yet? In that case, does SQLA expose a way for you to peek and see enough info about this eventual attribute to set things up? Or is ModelForm limited to including only backrefs that are defined with an actual class reference (as in the test), not Declarative's string references?

The latter would be annoying, since my case has the models in different files and there would be import issues.

YKdvd commented 9 years ago

I think I found what was happening. I had effectively done "only = ["locations"...], accidentally putting the relationship in the list of fields. validate_attribute was checking this list to see if they were all instances of ColumnProperty. A relationship isn't, but wtforms-alchemy throws InvalidAttributeException instead of AttributeTypeException, making me think it couldn't find the relationship.

Removing the relation from the "only" definition solves the problem, but I'd recommend that validate_attribute throw AttributeTypeException (which seems designed for this case) when failing the ColumnProperty instance check.