gpt4 book ai didi

python - 如何在 SQLAlchemy ORM 中查询多个表

转载 作者:行者123 更新时间:2023-12-03 19:07:07 27 4
gpt4 key购买 nike

我是 SQLAlchemy ORM 的新手,我正在努力在多个表上完成复杂的查询 - 我发现在 Doctrine DQL 中进行的查询相对简单。

我有属于国家的城市数据对象。一些城市也设置了县 ID,但不是全部。除了必要的主键和外键之外,每条记录还有一个 text_string_id,它链接到一个 TextStrings 表,该表存储了不同语言的城市/县/国家/地区的名称。 TextStrings MySQL 表如下所示:

CREATE TABLE IF NOT EXISTS `text_strings` (
`id` INT UNSIGNED NOT NULL,
`language` VARCHAR(2) NOT NULL,
`text_string` varchar(255) NOT NULL,
PRIMARY KEY (`id`, `language`)
)

我想为每个城市构建一个面包屑,形式如下:

country_en_name > city_en_name 或

country_en_name > County_en_name > city_en_name,

取决于是否为此城市设置了县属性。在 Doctrine 中,这相对简单:
    $query = Doctrine_Query::create()
->select('ci.id, CONCAT(cyts.text_string, \'> \', IF(cots.text_string is not null, CONCAT(cots.text_string, \'> \', \'\'), cits.text_string) as city_breadcrumb')
->from('City ci')
->leftJoin('ci.TextString cits')
->leftJoin('ci.Country cy')
->leftJoin('cy.TextString cyts')
->leftJoin('ci.County co')
->leftJoin('co.TextString cots')
->where('cits.language = ?', 'en')
->andWhere('cyts.language = ?', 'en')
->andWhere('(cots.language = ? OR cots.language is null)', 'en');

使用 SQLAlchemy ORM,我正在努力实现同样的目标。我相信我已经正确设置了对象 - 形式例如:
class City(Base):
__tablename__ = "cities"

id = Column(Integer, primary_key=True)
country_id = Column(Integer, ForeignKey('countries.id'))
text_string_id = Column(Integer, ForeignKey('text_strings.id'))
county_id = Column(Integer, ForeignKey('counties.id'))

text_strings = relation(TextString, backref=backref('cards', order_by=id))
country = relation(Country, backref=backref('countries', order_by=id))
county = relation(County, backref=backref('counties', order_by=id))

我的问题在于查询 - 我尝试了各种方法来生成面包屑,但似乎没有任何效果。一些观察:

也许在查询中使用内联 CONCAT 和 IF 之类的东西不是很pythonic(ORM甚至可能吗?) - 所以我尝试在SQLAlchemy之外,在记录的Python循环中执行这些操作。但是在这里我一直在努力访问各个字段 - 例如模型访问器似乎没有深入 n 级,例如City.counties.text_strings.language 不存在。

我还尝试过使用元组 - 我最接近它的方法是将其拆分为两个查询:
# For cities without a county
for city, country in session.query(City, Country).\
filter(Country.id == City.country_id).\
filter(City.county_id == None).all():

if city.text_strings.language == 'en':
# etc

# For cities with a county
for city, county, country in session.query(City, County, Country).\
filter(and_(City.county_id == County.id, City.country_id == Country.id)).all():

if city.text_strings.language == 'en':
# etc

我将其拆分为两个查询,因为我无法弄清楚如何仅在一个查询中使 Suit join 成为可选。但是这种方法当然很糟糕,更糟糕的是第二个查询没有 100% 工作 - 它没有加入所有不同的 city.text_strings 以进行后续过滤。

所以我很难过!您能给我的任何帮助让我走上正确的道路,以在 SQLAlchemy ORM 中执行这些复杂的查询,将不胜感激。

最佳答案

Suit 的映射不存在,但基于推进查询,我认为它有 text_strings属性。

描述带有连接的别名的 SQLAlchemy 文档的相关部分位于:

http://www.sqlalchemy.org/docs/orm/tutorial.html#using-aliases

函数的生成位于:

http://www.sqlalchemy.org/docs/core/tutorial.html#functions

cyts = aliased(TextString)
cits = aliased(TextString)
cots = aliased(TextString)
cy = aliased(Suit)
co = aliased(Suit)

session.query(
City.id,
(
cyts.text_string + \
'> ' + \
func.if_(cots.text_string!=None, cots.text_string + '> ', cits.text_string)
).label('city_breadcrumb')
).\
outerjoin((cits, City.text_strings)).\
outerjoin((cy, City.country)).\
outerjoin((cyts, cy.text_strings)).\
outerjoin((co, City.county))\
outerjoin((cots, co.text_string)).\
filter(cits.langauge=='en').\
filter(cyts.langauge=='en').\
filter(or_(cots.langauge=='en', cots.language==None))

虽然我认为只是说要简单得多:
city.text_strings.text_string + " > " + city.country.text_strings.text_string + " > " city.county.text_strings.text_string

如果你在 City, Suit 上加上一个描述符:
class City(object):
# ...
@property
def text_string(self):
return self.text_strings.text_string

那么你可以说 city.text_string .

关于python - 如何在 SQLAlchemy ORM 中查询多个表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4619959/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com