Question about the other property of backref

29 views
Skip to first unread message

尤立宇

unread,
Feb 24, 2016, 10:38:31 AM2/24/16
to sqlalchemy
Following the ORM tutorial of `User` and `Address`,
if I configure a `user` attribute on `Address`:

class Address(Base):
    __tablename__ = 'addresses'
    id = Column(Integer, primary_key=True)
    email_address = Column(String, nullable=False)
    user_id = Column(Integer, ForeignKey('users.id'))
    
    user = relationship('User', backref='addresses')

`User.addresses` is not available until I initiate a `User` or `Address` object.

According to the documentation of backref:

indicates the string name of a property to be placed on the related mapper’s class that will handle this relationship in the other direction. The other property will be created automatically when the mappers are configured.

What does it mean?

I'm using version 1.0.12 on Python 3.5.1

Thanks

Jonathan Vanasco

unread,
Feb 24, 2016, 11:24:40 AM2/24/16
to sqlalchemy
So in your example (simplified below)

    class User(Base):
        ...

    class Address(Base):
        ...
      user = relationship('User', backref='addresses')

when you create `Address.user` the `backref` command automatically creates the "other" side of the relationship -- `User.addresses`.

Another way to generate the same relationships would be:

    class User(Base):
        ...
      user = relationship('Address', back_populates='user')

    class Address(Base):
        ...
      user = relationship('User', back_populates ='addresses')


Many people "start out" with the first form, because automatically creating the relationship is very convenient.  As projects grow, it becomes much more convenient to use back_populates so you can see - and ensure - each side of the relationship on the appropriate class.  (Using `backref`, your relationship is only documented/appears in one class) 

尤立宇

unread,
Feb 25, 2016, 2:53:31 AM2/25/16
to sqlalchemy
Thanks for your response.

Do you consider using `backref` only on one of the class bad practice?

I'm curious because automatically creating descriptors seems possible to me, and I'm wondering when it happens.

As documentation states so:

Remember, when the backref keyword is used on a single relationship, it’s exactly the same as if the above two relationships were created individually using back_populates on each.

ref: http://docs.sqlalchemy.org/en/latest/orm/backref.html

There is also a half-a-year-old stackoverflow question about it:

http://stackoverflow.com/questions/32617371/how-to-force-creation-of-backref-instrumentedattributes-using-sqlalchemy

Simon King

unread,
Feb 25, 2016, 5:05:25 AM2/25/16
to sqlal...@googlegroups.com
I think it's a matter of personal preference. Some people like to see all the attributes of a class defined as part of the class definition itself, in which case they'll need to use 2 relationship definitions with the back_populates argument. Others prefer a terser syntax with less duplication, so they use the backref argument.

If you want to trigger the creation of all "pending" backref attributes, I think you can call sqlalchemy.orm.configure_mappers:


Normally this gets called automatically when you start querying the database, but in certain instances you may want to call it explicitly.

Simon

尤立宇

unread,
Feb 25, 2016, 6:08:28 AM2/25/16
to sqlalchemy
Thanks!

This is exactly what I was looking for.

Jonathan Vanasco

unread,
Feb 25, 2016, 12:58:06 PM2/25/16
to sqlalchemy


On Thursday, February 25, 2016 at 5:05:25 AM UTC-5, Simon King wrote:
 
I think it's a matter of personal preference. Some people like to see all the attributes of a class defined as part of the class definition itself, in which case they'll need to use 2 relationship definitions with the back_populates argument. Others prefer a terser syntax with less duplication, so they use the backref argument.

Exactly.

Another use-case though, is that you start your project with backref -- and you honestly do prefer it.  Eventually you have 100 tables that are highly relational, and backref becomes a bit of a liability when editing the code because you don't know if there is an 'incoming' relationship or not.  If you're using back_populates, sqlalchemy makes sure you define the association on each side.  slowly switching from backref to back_populates has really reduced the number of errors we make.

Reply all
Reply to author
Forward
0 new messages