Search code examples
pythonpeewee

Is there a way to get all backrefs a model has in peewee?


I have a BaseModel class that inherits from peewee.Model:

class BaseModel(peewee.Model):
     # Base Model code

My every model inherits from BaseModel. Some of my models are being referenced as Foreign Keys by others. Whenever I reference them as Foreign Keys, I set a backref, such as:

class Company(BaseModel):
     name = CharField(null=False)

class User(BaseModel):
     name = CharField(null=False)
     company = ForeignKeyField(Company, backref='users')

 class Campaign(BaseModel):
     name = CharField(null=False)
     created_by = ForeignKeyField(User, backref='campaigns')
     company = ForeignKeyField(Company, backref='campaigns')

Given an object whose class inherits from BaseModel, I would like a function that return as output a list of every backref I can use. For example, if I am given a company, I would like ['users', 'campaigns'] as output. If it is a user, then output would be ['campaigns']. Finally, a campaign would return [].

Is there a way I can achieve this?


Solution

  • Every model class stores the backrefs in ModelClass._meta.backrefs and ModelClass._meta.model_backrefs. You can recursively traverse these.

    Alternatively you can use ModelClass._meta.model_graph(refs=False, backrefs=True) which returns a list of 3-tuples (fk field, model class, is_backref).

    class Base(Model):
        class Meta:
            database = db
    
    class User(Base):
        username = TextField()
    
    class Tweet(Base):
        user = ForeignKeyField(User, backref='tweets')
    
    class Flag(Base):
        tweet = ForeignKeyField(Tweet, backref='flags')
        user = ForeignKeyField(User, backref='flags')
    
    
    >>> User._meta.backrefs
    {<ForeignKeyField: Tweet.user>: <Model: Tweet>,
     <ForeignKeyField: Flag.user>: <Model: Flag>}
    
    >>> User._meta.model_backrefs
    defaultdict(list,
                {<Model: Tweet>: [<ForeignKeyField: Tweet.user>],
                 <Model: Flag>: [<ForeignKeyField: Flag.user>]})
    
    >>> User._meta.model_graph(refs=False, backrefs=True)
    [(None, <Model: User>, None),
     (<ForeignKeyField: Tweet.user>, <Model: Tweet>, True),
     (<ForeignKeyField: Flag.user>, <Model: Flag>, True),
     (<ForeignKeyField: Flag.tweet>, <Model: Flag>, True)]