Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

backref class attribute

How to initialize backrefs of mappers without some queries through a session? For example, I have two models, named "Client" and "Subject" in follow code:

Base = declarative_base()

class Client(Base):
    __tablename__ = "clients"

    id = Column(Integer, primary_key=True)
    created = Column(DateTime, default=datetime.datetime.now)
    name = Column(String)

    subjects = relationship("Subject",  cascade="all,delete",
        backref=backref("client"))


class Subject(Base):
    __tablename__ = "subjects"

    id = Column(Integer, primary_key=True)
    client_id = Column(Integer, ForeignKey(Client.id, ondelete='CASCADE'))

Then, somewhere in my code, I want to get the backref client of the class Subject like this, but that raises an exception:

>>> Subject.client
AttributeError: type object 'Subject' has no attribute 'client'

After a query to Client like:

>>> session.query(Client).first()
>>> Subject.client
<sqlalchemy.orm.attributes.InstrumentedAttribute at 0x43ca1d0>

Attribute client was created after a query to the related model(mapper).
I don't want to make such "warming" queries!

like image 881
QBatman Avatar asked Feb 17 '13 13:02

QBatman


People also ask

What is Backref in DB relationship?

Using backref just automates the creation of a relationship property at the other end. backref='person' is somewhat akin to having person = db. relationship('Person') explicitly in the Address class (+ back population). Using the backref() object you can pass arguments to that relationship.

What is back populates?

Learn about Klaviyo's back-populate feature which allows you to queue people for flow actions retroactively. This is useful when you create a new flow, as back-populating allows you to populate contacts into your flow that would have been queued in real-time had the flow existed earlier.


2 Answers

Alternatively, you could use:

from sqlalchemy.orm import configure_mappers

configure_mappers()

This has the advantage that it creates all the backrefs for all your models in one step.

like image 54
mtth Avatar answered Oct 17 '22 08:10

mtth


Because SQLAlchemy uses metaclasses, the code that creates the back reference on the other class won't run until you have created at least one instance of the Client class.

The remedy is simple: create a Client() instance, and discard it again:

>>> Subject.client
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'Subject' has no attribute 'client'
>>> Client()
<__main__.Client object at 0x104bdc690>
>>> Subject.client
<sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x104be9e10>

or use the configure_mappers utility function:

from sqlalchemy.orm import configure_mappers

to scan your models for such references and initialize them. Creating any one instance calls this method under the hood, actually.

like image 6
Martijn Pieters Avatar answered Oct 17 '22 07:10

Martijn Pieters