kvesteri / wtforms-alchemy

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

Relationship breaks ModelForm? #119

Closed vincentwhales closed 7 years ago

vincentwhales commented 7 years ago

I have two models: Cloaker and Account. Note that I have simplified both classes for the sake of this question.

automata/cloaker/models.py

class Cloaker(db.Model):
  __tablename__ = 'cloaker'

  id = db.Column(db.Integer, primary_key=True)
  account = db.relationship("Account", uselist=False, back_populates="cloaker")

class CloakerForm(ModelForm):
  class Meta:
    model = Cloaker

automata/account/models.py

class Account(db.Model):
  __tablename__ = 'account'

  id = db.Column(db.Integer, primary_key=True)
  cloaker_id = db.Column(db.Integer, db.ForeignKey(Cloaker.id))
  cloaker = db.relationship(Cloaker, back_populates='account')

When I run flask, I am getting the following error:

Traceback (most recent call last):
  File "manage.py", line 6, in <module>
    from automata import app, db
  File "/Users/vng/Dropbox/Code/Affiliate/AutomataHeroku/automata/__init__.py", line 6, in <module>
    from automata.cloaker import cloaker_bp
  File "/Users/vng/Dropbox/Code/Affiliate/AutomataHeroku/automata/cloaker/__init__.py", line 8, in <module>
    from .models import Cloaker, CloakerForm, Task, Template, TemplateForm
  File "/Users/vng/Dropbox/Code/Affiliate/AutomataHeroku/automata/cloaker/models.py", line 203, in <module>
    class CloakerForm(ModelForm):
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/wtforms_alchemy/__init__.py", line 116, in __init__
    generator.create_form(cls)
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/wtforms_alchemy/generator.py", line 142, in create_form
    for key, property_ in sa.inspect(self.model_class).attrs.items():
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 764, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2165, in attrs
    configure_mappers()
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 2866, in configure_mappers
    mapper._post_configure_properties()
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/orm/mapper.py", line 1765, in _post_configure_properties
    prop.init()
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/orm/interfaces.py", line 184, in init
    self.do_init()
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1652, in do_init
    self._process_dependent_arguments()
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1709, in _process_dependent_arguments
    self.target = self.mapper.mapped_table
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 764, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 1625, in mapper
    argument = self.argument()
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/sqlalchemy/ext/declarative/clsregistry.py", line 293, in __call__
    (self.prop.parent, self.arg, n.args[0], self.cls)
sqlalchemy.exc.InvalidRequestError: When initializing mapper Mapper|Cloaker|cloaker, expression 'Account' failed to locate a name ("name 'Account' is not defined"). If this is a class name, consider adding this relationship() to the <class 'automata.cloaker.models.Cloaker'> class after both dependent classes have been defined.

What is causing this error?

kvesteri commented 7 years ago

This is an issue of how you've setup your model relationships. It doesn't have anything to do with WTForms-Alchemy. See SA documentation of how to set-up backref relationships.

vincentwhales commented 7 years ago

Actually I beg to differ.

File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/wtforms_alchemy/__init__.py", line 116, in __init__
    generator.create_form(cls)
  File "/Users/vng/.virtualenvs/AutomataHeroku/lib/python2.7/site-packages/wtforms_alchemy/generator.py", line 142, in create_form
    for key, property_ in sa.inspect(self.model_class).attrs.items():

I believe this error is caused by WTForms-Alchemy generating the ModelForm which invokes this line, for key, property_ in sa.inspect(self.model_class).attrs.items(), before the model (Account in this case) is defined.

This is happening because the creation of a ModelForm involves inspecting the attributes of that form. Some of these attributes are relationship attributes defined by backref/back_populates. These relationships reference another model that is not yet defined.

Is there anyway to fix this?

kvesteri commented 7 years ago

Perhaps you could lazily generate your forms using factory or by placing the form in a separate file and making sure models are configured before the form definition (by calling for example sqlalchemy.orm.configure_mappers())