Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQLAlchemy - AttributeError: _reverse_property

I'm having some trouble working and learning SQLALCHEMY and I think the issue is to do with my back_populates in relationships, but I've not been able to suss it out. Can you please point me in the right direction?

The tables are created successfully and everything seems to be in order until I try and create a new MailProvider, which causes this error:

Traceback (most recent call last):
  File "C:/Users/Music/.PyCharm2016.2/config/scratches/scratch_7.py", line 71, in <module>
    gmail = MailProvider(service_provider="gmail.com")
  File "<string>", line 2, in __init__
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\orm\instrumentation.py", line 347, in _new_state_if_none
    state = self._state_constructor(instance, self)
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\util\langhelpers.py", line 754, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\orm\instrumentation.py", line 177, in _state_constructor
    self.dispatch.first_init(self, self.class_)
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\event\attr.py", line 256, in __call__
    fn(*args, **kw)
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\orm\mapper.py", line 2872, in _event_on_first_init
    configure_mappers()
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\orm\mapper.py", line 2768, in configure_mappers
    mapper._post_configure_properties()
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\orm\mapper.py", line 1708, in _post_configure_properties
    prop.init()
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\orm\interfaces.py", line 183, in init
    self.do_init()
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\orm\relationships.py", line 1632, in do_init
    self._generate_backref()
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\orm\relationships.py", line 1866, in _generate_backref
    self._add_reverse_property(self.back_populates)
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\orm\relationships.py", line 1574, in _add_reverse_property
    other._reverse_property.add(self)
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\util\langhelpers.py", line 840, in __getattr__
    return self._fallback_getattr(key)
  File "C:\Users\Music\mailtesterV2\lib\site-packages\sqlalchemy\util\langhelpers.py", line 818, in _fallback_getattr
    raise AttributeError(key)
AttributeError: _reverse_property

My Code:

from sqlalchemy import Column, ForeignKey, Integer, String, Boolean, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy import create_engine

engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)

Base = declarative_base()

class MailProvider(Base):
    __tablename__ = 'mail_provider'

    id = Column(Integer, primary_key=True)
    service_provider = Column(String(250), nullable=False)

    imap_server = Column(String(250))
    imap_server_port = Column(Integer)
    imap_server_ssl = Column(String(250))
    imap_server_port_ssl = Column(Integer)
    imap_server_use_tls = Column(Boolean)

    smtp_server = Column(String(250))
    smtp_server_port = Column(Integer)
    smtp_server_ssl = Column(String(250))
    smtp_server_port_ssl = Column(Integer)
    smtp_server_use_tls = Column(Boolean)

class MailAccount(Base):
    __tablename__ = "mail_account"

    id = Column(Integer, primary_key=True)
    email_address = Column(String(250), nullable=False)
    imap_username = Column(String(250), nullable=False)
    imap_password = Column(String(250), nullable=False)
    smtp_username = Column(String(250), nullable=False)
    smtp_password = Column(String(250), nullable=False)
    provider_id = Column(Integer, ForeignKey('mail_provider.id'), nullable=False)
    provider = relationship("MailProvider", back_populates="service_provider")
    account_owner = Column(String(250), nullable=False)

class SentMail(Base):
    __tablename__ = "sent_mail"

    id = Column(Integer, primary_key=True)
    mail_uuid = Column(String(36), nullable=False)
    time_sent = Column(DateTime(timezone=True), nullable=False)
    sent_from_id = Column(Integer, ForeignKey('mail_account.id'), nullable=False)
    sent_from = relationship("MailAccount", back_populates="email_address")
    sent_to = Column(String(250), nullable=False)
    msg_subject = Column(String(250))
    msg_body = Column(String)
    send_status = Column(String(500))

class ReceivedMail(Base):
    __tablename__ = "received_mail"

    id = Column(Integer, primary_key=True)
    sent_mail_id = Column(Integer, ForeignKey('sent_mail.id'), nullable=False)
    sent_mail = relationship("SentMail", back_populates="mail_uuid")
    time_received = Column(DateTime(timezone=True), nullable=False)


MailProvider.accounts = relationship("MailAccount", back_populates="provider", order_by="MailAccount.id")
MailAccount.mails_sent = relationship("SentMail", back_populates="mail_uuid", order_by="SentMail.time_sent")
SentMail.received_mails = relationship("RecievedMail", back_populates="received_time", order_by="RecievedMail.received_time")

Base.metadata.create_all(engine)
session = Session()
gmail = MailProvider(service_provider="gmail.com")

session.add(gmail)
session.commit()
like image 472
Awebb Avatar asked Sep 08 '16 17:09

Awebb


1 Answers

Relationship back_populates reference other relationships, not columns.

Revised code:

from sqlalchemy import Column, ForeignKey, Integer, String, Boolean, DateTime
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy import create_engine

engine = create_engine('sqlite:///:memory:', echo=True)
Session = sessionmaker(bind=engine)

Base = declarative_base()

class MailProvider(Base):
    __tablename__ = 'mail_provider'

    id = Column(Integer, primary_key=True)
    service_provider = Column(String(250), nullable=False)

    imap_server = Column(String(250))
    imap_server_port = Column(Integer)
    imap_server_ssl = Column(String(250))
    imap_server_port_ssl = Column(Integer)
    imap_server_use_tls = Column(Boolean)

    smtp_server = Column(String(250))
    smtp_server_port = Column(Integer)
    smtp_server_ssl = Column(String(250))
    smtp_server_port_ssl = Column(Integer)
    smtp_server_use_tls = Column(Boolean)

    accounts = relationship("MailAccount", back_populates="provider")

class MailAccount(Base):
    __tablename__ = "mail_account"

    id = Column(Integer, primary_key=True)
    email_address = Column(String(250), nullable=False)
    imap_username = Column(String(250), nullable=False)
    imap_password = Column(String(250), nullable=False)
    smtp_username = Column(String(250), nullable=False)
    smtp_password = Column(String(250), nullable=False)
    provider_id = Column(Integer, ForeignKey('mail_provider.id'), nullable=False)
    provider = relationship("MailProvider", back_populates="accounts")
    account_owner = Column(String(250), nullable=False)
    mails_sent = relationship("SentMail", back_populates="sent_from", order_by="SentMail.time_sent")

class SentMail(Base):
    __tablename__ = "sent_mail"

    id = Column(Integer, primary_key=True)
    mail_uuid = Column(String(36), nullable=False)
    time_sent = Column(DateTime(timezone=True), nullable=False)
    sent_from_id = Column(Integer, ForeignKey('mail_account.id'), nullable=False)
    sent_from = relationship("MailAccount", back_populates="mails_sent")
    sent_to = Column(String(250), nullable=False)
    msg_subject = Column(String(250))
    msg_body = Column(String)
    send_status = Column(String(500))
    received_mails = relationship("ReceivedMail", back_populates="sent_mail", order_by="ReceivedMail.time_received")

class ReceivedMail(Base):
    __tablename__ = "received_mail"

    id = Column(Integer, primary_key=True)
    sent_mail_id = Column(Integer, ForeignKey('sent_mail.id'), nullable=False)
    sent_mail = relationship("SentMail", back_populates="received_mails")
    time_received = Column(DateTime(timezone=True), nullable=False)

Base.metadata.create_all(engine)
session = Session()
gmail = MailProvider(service_provider="gmail.com")

session.add(gmail)
session.commit()
like image 159
Awebb Avatar answered Oct 21 '22 04:10

Awebb