SQLAlchemy: AttributeError: 'table' object has no attribute 'id'
I am building a database that matches my local product catalog with foreign product catalogs. 'Catalog'
SQLAlchemy works fine when I have only unique tables . After adding the tables Competitors
, Competitors_catalog
all attempts to add records to the two new tables return errors.
AttributeError: 'table' object has no attribute 'id'
There are relationships I change/delete/play Competitors
and Competitors_catalog
drop multiple times and go back and forth through creating the table flask-migrate
, but keep getting the same error. A simple query like this Competitors.query.all()
returns the same result. Removed db.relationship()
- same result. Then I finally rolled back to a clean database and started it flask-migrate
from scratch . After that I started getting the same error when trying to add records to the Catalog
table, before rolling back it worked fine. Strange because I didn't make any 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())
Simply creating a new instance will return an error. But it worked fine before rollback.
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'
The remote_side
parameter can be passed as an evaluated string, which you do:
remote_side='catalog.id'
The problem is that the namespace evaluated in it contains Table
object and model classes, and you are referencing Table
the model class instead of the model class. Just change the far end to
remote_side='Catalog.id'
or pass the column id
directly in the class body :
class Catalog(db.Model):
__tablename__ = 'catalog'
id = db.Column(db.Integer, primary_key=True)
...
categories = db.relationship('Catalog', remote_side=id, backref='parent')