0

Attempting a one-to-many relationship between an outbound email (child), the source (parent 1) and target (parent 2). I am attempting to use flask-migrate for the setup of the database. The command I'm using:

python manage.py db migrate

Getting the following error:

sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'outbound_emails.target_id' could not find table 'targets' with which to generate a foreign key to target column 'id'

Here's what I have so far:

class Contact(Base):
    __abstract__ = True
    id = db.Column(db.Integer, primary_key=True)
    first_name = db.Column(db.Text, nullable=False)
    last_name = db.Column(db.Text, nullable=False)
    email = db.Column(db.Text, nullable=False)
    phone = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow())
    last_activity = db.Column(db.DateTime, default=datetime.utcnow())
    json_data = db.Column(sqlalchemy.dialects.postgresql.JSON)

    def __init__(self, first_name, last_name, email, phone,
                 created_date=datetime.utcnow(), last_activity=datetime.utcnow(), json_data=None):
        if json_data is None:
            json_data = {}
        self.first_name = first_name
        self.last_name = last_name
        self.email = email
        self.phone = phone
        self.created_date = created_date
        self.last_activity = last_activity
        self.json_data = json_data


class Target(Contact):
    __tablename__ = 'targets'
    outbound_emails = db.relationship("OutboundEmail", backref="target", lazy='dynamic')

    @property
    def __repr__(self):
        return '<target_id {}>'.format(self.target_id)


class Source(Contact):
    __tablename__ = 'sources'
    outbound_emails = db.relationship("OutboundEmail", backref="source", lazy='dynamic')

    @property
    def __repr__(self):
        return '<source_id {}>'.format(self.source_id)


class OutboundEmail(db.Model):
    __tablename__ = 'outbound_emails'
    email_id = db.Column(db.Integer, primary_key=True)
    provider_id = db.Column(db.Text, nullable=True)
    source_id = db.Column(db.Integer, db.ForeignKey("sources.id"))
    target_id = db.Column(db.Integer, db.ForeignKey("targets.id"))
    data = db.Column(sqlalchemy.dialects.postgresql.JSON)

    def __init__(self, provider_id, source, target, merge_fields):
        self.provider_id = provider_id
        self.source = source
        self.target = target
        self.data = merge_fields


    @property
    def __repr__(self):
        return '<email_id {}>'.format(self.email_id)

Does anybody see what I'm doing wrong here? Thanks!

davidism
  • 121,510
  • 29
  • 395
  • 339

1 Answers1

0

The solution may depend on which type of inheritance you are trying to achieve, either single table, concrete table or joined table inheritance.

Considering that you have marked your base class as _abstract_ I suppose that you want to map each subclass to its own distinct table, thus using a form of concrete inheritance.

In that case you need to define all columns explicitly on each subclass, even those of the same name. So at least you need to set:

id = db.Column(db.Integer, primary_key=True)

on your derived classes.

In addition to that, you may also need to set a polymorphic identity in your subclasses, and possibly extend it to allow polymorphic loading. I suggest to take a look at the wonderful SQLAlchemy documentation on this topic.

lec00q
  • 170
  • 1
  • 9