Reputation: 13
I'm building a DB, that matches my local product catalogue with foreign ones. When I had the only table 'Catalog'
SQLAlchemy worked fine. After adding tables Competitors
and Competitors_catalog
all my attempts to add records to both new tables returned with error.
AttributeError: 'Table' object has no attribute 'id'
I change/remove/play with relationship between Competitors
and Competitors_catalog
several times, drop and create tables through flask-migrate
back and forth, but keep receiving same error.
Simple query like Competitors.query.all()
returns the same.
Removed db.relationship()
- same result.
Then I finally rolled back to a clear db and initiated it with flask-migrate
from scratch. After that I begin to receive same error trying to add records to Catalog
table, which worked fine before I rolled back. Which is odd since I made no changes to that part of the code.
class Catalog(db.Model):
__tablename__ = 'catalog'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(60), index=True, nullable=False)
parent_id = db.Column(db.Integer, db.ForeignKey('catalog.id'), default=None)
url = db.Column(db.String())
created = db.Column(db.DateTime, default=datetime.now())
last_modified = db.Column(db.DateTime, index=True, onupdate=datetime.now())
categories = db.relationship('Catalog', remote_side='catalog.id', backref='parent')
class Competitors(db.Model):
__tablename__ = 'competitors'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(40), index=True, nullable=False)
base_url = db.Column(db.String())
cat_url = db.Column(db.String())
created = db.Column(db.DateTime, default=datetime.now())
last_modified = db.Column(db.DateTime, onupdate=datetime.now(), default=datetime.now())
sells = db.relationship('Competitors_catalog', backref='competitor', cascade="all, delete-orphan", passive_deletes=True, lazy='dynamic')
class CompCatalog(db.Model):
__tablename__ = 'compcatalog'
id = db.Column(db.Integer, primary_key=True)
out_id = db.Column(db.Integer)
name = db.Column(db.String(60), index=True, nullable=False)
top_section = db.Column(db.Integer, default=None)
comp_id = db.Column(db.Integer, db.ForeignKey('competitors.id', ondelete="CASCADE"))
url = db.Column(db.String())
created = db.Column(db.DateTime, default=datetime.now())
last_modified = db.Column(db.DateTime, index=True, onupdate=datetime.now())
Simple creation of new instance returns error. But worked fine before roll back.
from .models import Catalog
name = 'Apple'
rec = Catalog(name=name)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File ".../app/helpers.py", line 31, in create_catalog
rec = Catalog(name=name)
File "<string>", line 2, in __init__
File ".../.virtualenvs/.../lib/python3.6/site-packages/sqlalchemy/orm/instrumentation.py", line 376, in _new_state_if_none
state = self._state_constructor(instance, self)
File ".../.virtualenvs/.../lib/python3.6/site-packages/sqlalchemy/util/langhelpers.py", line 855, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File ".../.virtualenvs/.../lib/python3.6/site-packages/sqlalchemy/orm/instrumentation.py", line 202, in _state_constructor
self.dispatch.first_init(self, self.class_)
File ".../.virtualenvs/.../lib/python3.6/site-packages/sqlalchemy/event/attr.py", line 322, in __call__
fn(*args, **kw)
File ".../.virtualenvs/.../lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", line 3360, in _event_on_first_init
configure_mappers()
File ".../.virtualenvs/.../lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", line 3248, in configure_mappers
mapper._post_configure_properties()
File ".../.virtualenvs/.../lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", line 1947, in _post_configure_properties
prop.init()
File ".../.virtualenvs/.../lib/python3.6/site-packages/sqlalchemy/orm/interfaces.py", line 196, in init
self.do_init()
File ".../.virtualenvs/.../lib/python3.6/site-packages/sqlalchemy/orm/relationships.py", line 1860, in do_init
self._process_dependent_arguments()
File ".../.virtualenvs/.../lib/python3.6/site-packages/sqlalchemy/orm/relationships.py", line 1889, in _process_dependent_arguments
setattr(self, attr, attr_value())
File ".../.virtualenvs/.../lib/python3.6/site-packages/sqlalchemy/ext/declarative/clsregistry.py", line 294, in __call__
x = eval(self.arg, globals(), self._dict)
File "<string>", line 1, in <module>
AttributeError: 'Table' object has no attribute 'id'
Upvotes: 1
Views: 10791
Reputation: 52929
The remote_side
argument can be passed as an evaluable string, which you've done:
remote_side='catalog.id'
The problem is that the namespace it is evaluated in contains the Table
objects and the model classes, and you're referencing a Table
instead of the model class. Just alter the remote side to
remote_side='Catalog.id'
or just pass the id
column in the class body directly:
class Catalog(db.Model):
__tablename__ = 'catalog'
id = db.Column(db.Integer, primary_key=True)
...
categories = db.relationship('Catalog', remote_side=id, backref='parent')
Upvotes: 2