遇到一個問題,請各位給講解一下sqlalchemy中的backref?

from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
name = Column(String)

addresses = relationship("Address", backref="user")

class Address(Base):
__tablename__ = "address"
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = Column(Integer, ForeignKey("user.id"))

我先說說我的理解,通過relationship的第一個Address參數,user表可以獲取到address表中的多個地址,那backref的作用呢?查了很多文檔,只是簡單說明通過backref創建了動態關係,不太懂,是不是智商真的不夠呢?

另外還有下面這種backref = db.backref更加不懂了。

class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50))
addresses = db.relationship("Address",
backref=db.backref("person", lazy="joined"), lazy="dynamic")


簡單來說, relationship函數是sqlalchemy對關係之間提供的一種便利的調用方式, backref參數則對關係提供反向引用的聲明。

假如沒有relationship,我們只能像下面這樣調用關係數據。

#給定參數User.name,獲取該user的addresses

def get_addresses_from_user(user_name):
user = session.query(User).filter_by(name=user_name).first()
addresses = session.query(Address).filter_by(user_id=user.id).all()
return addresses

如果在User中使用relationship定義addresses屬性的話,

addresses = relationship("Address")

則我們可以直接在User對象中通過addresses屬性獲得指定用戶的所有地址。

def get_addresses_from_user(user_name):
user = session.query(User).filter_by(name=user_name).first()
return user.addresses

注意,在上面的addresses屬性中我們並沒有定義backref屬性,所以我們可以通過User對象獲取所擁有的地址,但是不能通過Address對象獲取到所屬的用戶.

&>&>&> u = User()
&>&>&> u.addresses
[]
&>&>&> a = Address()
&>&>&> a.user
Traceback (most recent call last):
File "&", line 1, in &
AttributeError: "Address" object has no attribute "user"

但是當我們有從Address對象獲取所屬用戶的需求時,backref參數就派上用場了。

addresses = relationship("Address", backref="user")

&>&>&> a = Address()
&>&>&> a.user

大致原理應該就是sqlalchemy在運行時對Address對象動態的設置了一個指向所屬User對象的屬性,這樣就能在實際開發中使邏輯關係更加清晰,代碼更加簡潔了。

至於backref=backref("user", lazy="dynamic")這種用法,翻看一下backref源碼便能知曉。

def backref(name, **kwargs):
"""Create a back reference with explicit keyword arguments, which are the same arguments one can send to :func:`relationship`.

Used with the ``backref`` keyword argument to :func:`relationship` in
place of a string argument, e.g.::

"items":relationship(
SomeItem, backref=backref("parent", lazy="subquery"))

.. seealso::

:ref:`relationships_backref`

"""

return (name, kwargs)

:param 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. Can also be passed as a
:func:`.backref` object to control the configuration of the
new relationship.

最後需要注意的是在最新版本的sqlalchemy中對relationship引進了back_populates參數。

Note

The relationship.back_populates parameter is a newer version of a very common SQLAlchemy feature called relationship.backref. The relationship.backref parameter hasn』t gone anywhere and will always remain available! The relationship.back_populates is the same thing, except a little more verbose and easier to manipulate. For an overview of the entire topic, see the section Linking Relationships with Backref.

這個參數和backref的區別是只提供單向的關係引用,且必須成對存在,但是完成的功能和backref是一樣的,具體用法參見http://docs.sqlalchemy.org/en/rel_1_0/orm/tutorial.html。


最近也在看這快,說下自己的理解。關係函數和反向引用其實就是連接兩個表的橋樑,具體可以看下最高票的答案,講的很詳細。通過橋樑,我們可以直接一個表中通過屬性直接訪問另一個表,這就是好處所在。但是relationship函數的返回值所定義的屬性,和我們定義的反向引用屬性是不同的。使用反向引用屬性得到的是另一個模型的對象實例,而函數返回值定義的屬性得到的不是。


請看文檔

Linking Relationships with Backref

和源代碼

def backref(name, **kwargs): """Create a back reference with explicit keyword arguments, which are the same arguments one can send to :func:`relationship`. Used with the ``backref`` keyword argument to :func:`relationship` in place of a string argument, e.g.:: "items":relationship( SomeItem, backref=backref("parent", lazy="subquery")) .. seealso:: :ref:`relationships_backref` """
return (name, kwargs)


flask-sqlalchemy中 backref lazy的參數實例解釋和選擇

SQLalchemy relationship之lazy屬性 學習筆記

把這兩篇文章仔細看一遍應該就差不多了。


一對多:一個父親可能有多個孩子

1 class Father(……):
2 id = ……
3 children = db.relationship("Children", backref="father")
4
5 class Children(……):
6 # ……
7 father_id = …… ForeignKey("father.id"))


1 我是爸爸

2 我是身份證號

3 我有一些孩子登記在Children表上。上面的每一個children都可以通過 . father找到我。backref是我給孩子們的名片(上面是身份證號)

4

5 我們是孩子們

6

7 我拿著爸爸的身份證號


當我們需要在父表中添加子表關係時使用 relationship,外鍵通常是父表的主鍵


backref = db.backref("person", lazy="joined"), lazy="dynamic")一般用在子表中,父表(某一欄位被其他類引用為外鍵)中使用的是backref =『user』


推薦閱讀:

如何理解python的sqlalchemy這種orm框架?

TAG:資料庫 | Python | SQL | SQLAlchemy | Flask |