格式化SQLAlchemy代码

时间:2012-02-28 00:06:34

标签: python formatting sqlalchemy pep8

我们正在尝试按照PEP8指南格式化我们的Python代码并保持每行80个字符以下。

我们的SQLAlchemy行特别麻烦,拥有大量链接方法和大量复杂参数,逻辑和嵌套函数。

是否有任何使用PEP8约束格式化Python SQLAlchemy的特定最佳实践?

我找到的最接近的答案是here,但我正在处理的代码远非复杂。

4 个答案:

答案 0 :(得分:28)

来到这里希望有更好的解决方案,但我认为我更喜欢括号包装样式:

subkeyword = (
    Session.query(
        Subkeyword.subkeyword_id, 
        Subkeyword.subkeyword_word
    )
    .filter_by(subkeyword_company_id=self.e_company_id)
    .filter_by(subkeyword_word=subkeyword_word)
    .filter_by(subkeyword_active=True)
    .one()
)

这很好而且清晰,避免了可怕的反斜杠。

答案 1 :(得分:8)

pep-8不鼓励使用反斜杠但是对于SQLAlchemy代码我不禁认为它们是最具可读性的,因为你可以将每个生成函数保留在它自己的行的开头。如果括号内有很多参数,我也会在各行中将它们分开。

subkeyword = Session.query(
                  Subkeyword.subkeyword_id, 
                  Subkeyword.subkeyword_word
             ).\
               filter_by(subkeyword_company_id=self.e_company_id).\
               filter_by(subkeyword_word=subkeyword_word).\
               filter_by(subkeyword_active=True).\
               one()

当然,无论代码有多复杂,都可以对任何数量的代码进行缩进模式,但是在Python中我们希望避免过多的嵌套。通常使用Query会发生嵌套,因为您正在组合多个子查询。所以一定要提前构建子查询:

subq = Session.query(
                Bat.id, 
                func.foo(Bat.x, Bat.y).label('foo')
               ).\
                filter(Bat.id==Bar.name).\
                correlate(Bar).\
                subquery()

subq2 = Session.query(Foo.id, Foo.bar).\
                filter_by(flag>5).\
                subquery()

result = Session.query(
                  subq.c.id,
                  subq.c.foo,
                  subq2.c.bar
                ).\
                join(subq2, 
                     and_(
                      subq.c.id > subq2.c.foo, 
                      subq.bar == subq2.id
                     )
                ).\
                order_by(subq.c.id, subq2.c.bar)

我欢迎其他关于反斜杠的意见。

答案 2 :(得分:2)

我经常使用反斜杠的方式与zzzeek在答案中指出的方式类似。 PEP8只是一个指导原则,当你违反它时不要失去睡眠!

但是,我也经常使用下面的格式类型,我偷了zzzeek的第一个例子,温和地调整它,并重新格式化:

q = Session.query(
    Subkeyword.subkeyword_id, 
    Subkeyword.subkeyword_word,
)
q = q.filter_by(subkeyword_company_id=self.e_company_id)  # first filter
q = q.filter_by(subkeyword_word=subkeyword_word)  # 2nd filter
q = q.filter_by(subkeyword_active=True)

if filter_by_foo:
    q = q.filter(Subkeyword.foo == True)

# Run the query (I usually wrap in a try block)...
subkeyword = q.one()

一开始,对q的重复调整似乎有些令人讨厌,但我已经克服了它。性能影响实际上是零。这种方式的一个很大的优点是你可以混合使用尾随注释和注释行来记录你的查询(就像我上面的无用添加一样)。带有反斜杠的链条限制了你。

在使用大量逻辑触发修改,嵌入式标量选择等制定大量查询时,这种格式化方式特别干净。

作为另一个例子,我有一个相当大的(> 150行)CTE查询我在SQLAlchemy中生成,它有很多混合逻辑,别名和标签(这对于生成的查询的可读性至关重要)混合两种方法。一个严重减少(和损坏)的版本开始如下所示:

cte_init = session.\
    query(
        child1.foo.label("child1_foo"),
        sa.literal(1).label("indent"),  # can comment on non-slashed lines
        child2.bar.label("child2bar"),
        #comments between non-slashed lines ok, too 
        sa.func.MAX(toplevel.baz).label("max_baz"),
    ).\
    select_from(top_level).\
    join(child1,
         child1.id == toplevel.fk_child1_id).\
    join(child2.
         child2.id == toplevel.fk_child2.id).\
    filter(top_level.name == "bogus").\
    cte(name = "cte", recursive = True)

if(use_filter_x):
    cte_init = cte_init.filter_by(x = "whatever")

# etc (no, the above doesn't make any sense)...

一般情况下,如果确保使用新操作(例如许多常见的SQL格式化方案)来引导线路,则它仍然具有可读性。也不要害怕括号内的换行符。

答案 3 :(得分:1)

是的,无论你做什么,这些都会变得很讨厌,所以你可以将这些结构分成更短的行,但肯定会这样做。

如果不能,您可以通过将整个RHS放在括号中来摆脱所有这些反斜杠。然后Python会在没有反斜杠的情况下正确解析多行结构,但它也很难说是否更好。在这样的情况下,我认为你只需要用你最好的判断力,抓住你的鼻子并投入其中。