Adding a foreign key dynamically

112 views
Skip to first unread message

RexE

unread,
Jan 11, 2021, 10:20:12 PM1/11/21
to sqlalchemy
I'm changing my framework to use the SQLAlchemy declarative system internally. However, I want to keep the API the same. Here is how users of my framework declare a foreign key:

from myframework import Model, Link

class Bar(Model)

class Foo(Model):
  bar = Link(Bar)

At first I thought I could simply change the implementation of Link to this:

def Link(cls):
  return relationship(cls.__name__)

But actually I see that in SQLAlchemy I also need an Integer column that contains the id. So, I think I would need to patch the class at runtime to ensure these 2 attributes are defined. First, I would make a simple definition of Link to store the class it points to:

class Link:
  def __init__(self, cls):
    self.cls = cls

Then after I import the user's module, I patch all subclasses of Model:

for cls in Model.__subclasses__():
    for k, v in list(cls.__dict__.items()):
        if isinstance(v, Link):
            ClsName = v.cls.__name__
            setattr(cls, k, relationship(f'{cls.__module__}.{ClsName}'))
            setattr(
                cls,
                f'{k}_id',
                Column(
                    Integer,
                    ForeignKey(f'{cls.__tablename__}_{ClsName.lower()}.id'),
                ),
            )

However, I get this:

sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'live_bid.player_id' could not find table 'live_bid_player' with which to generate a foreign key to target column 'id'

I guess I am patching it too late. My next idea is to put this patching code inside the metaclass of Model, but before I go too far down the wrong path I wanted to ask here if there is a better way :)

Thank you!

Mike Bayer

unread,
Jan 11, 2021, 10:39:13 PM1/11/21
to noreply-spamdigest via sqlalchemy
Likely patching too early.   For this kind of thing you want to use an event like "mapper_configured" , which will give you a space where a particular mapper is all set up, all the Table objects needed should have been defined, and you can add additional attributes.   there's a ten-year-old example of what you are trying to do at https://techspot.zzzeek.org/2011/05/17/magic-a-new-orm/.   the code there seems to be mostly still how things work.







Thank you!


--
SQLAlchemy -
The Python SQL Toolkit and Object Relational Mapper
 
 
To post example code, please provide an MCVE: Minimal, Complete, and Verifiable Example. See http://stackoverflow.com/help/mcve for a full description.
---
You received this message because you are subscribed to the Google Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sqlalchemy+...@googlegroups.com.

RexE

unread,
Jan 12, 2021, 2:55:49 AM1/12/21
to sqlalchemy
OK thank you! I will give it a try.
Reply all
Reply to author
Forward
0 new messages