【问题标题】:Django Style: Long queries?Django 风格:长查询?
【发布时间】:2011-10-28 17:51:14
【问题描述】:

我有一些相当长(约 150 个字符)的 django 查询。将它们分成多行的首选方法是什么?

例如(不,不是我的真实代码):

编辑:更改了示例,因为人们关注的是重复过滤器,而不是查询的长度:

person = models.UzbekistaniCitizen.objects.filter(occupation__income__taxable__gte=40000).exclude(face__eyes__color=blue).order_by('height').select_related('siblings', 'children')

我能想到的方法有两种:

  1. 使用反斜杠作为换行符:

    person = models.UzbekistaniCitizen.objects.\
                              filter(occupation__income__taxable__gte=40000).\
                              exclude(face__eyes__color=blue).\
                              order_by('height').\
                              select_related('siblings', 'children')
    
  2. 在新行中重新应用过滤器:

    person = models.UzbekistaniCitizen.objects
    person = person.(occupation__income__taxable__gte=40000)
    person = person.exclude(face__eyes__color=blue)
    person = person.order_by('height')
    person = person.select_related('siblings', 'children')
    

【问题讨论】:

    标签: django coding-style


    【解决方案1】:

    您可以在整个 rhs 周围使用括号来获得隐含的续行:

    person = (models.UzbekistaniCitizen
                    .objects
                    .filter(occupation__income__taxable__gte=40000)
                    .exclude(face__eyes__color=blue)
                    .order_by('height')
                    .select_related('siblings', 'children'))
    

    【讨论】:

    • 这是迄今为止最易读的。我刚刚在一些开源代码中看到了这一点。我不敢相信我多年来一直在编写 python 却不知道这一点。这种语法有什么缺点吗?
    • 不,根本没有。我有一段时间避免使用它,因为我担心它会被解释为元组定义。在实践中,这是一种毫无根据的恐惧,一个单位元组 defs 必须有尾随逗号的原因变得更加清楚:(1,) 而不是 (1)。
    • 出于同样的原因,我避免使用它,认为它会变成一个元组。从来没想过结尾的逗号,非常好的答案。
    【解决方案2】:

    我的风格很好

    person = (
        models
        .UzbekistaniCitizen
        .objects
        .filter(occupation__income__taxable__gte=40000)
        .exclude(face__eyes__color=blue)
        .order_by('height')
        .select_related('siblings', 'children')
    )
    

    这种风格,最方便的是不用手动缩进,每行缩进几个4个空格。

    以下缺点: 1.如果你重命名变量person,你必须手动调整缩进。 2.如果你的模型名很长,每行80个字符是很难限制的。

    person = UzbekistaniCitizen.objects.myfilter(hair__color=brown,
                                                eye__color= blue,
                                                height__gt= 56,
                                                ...
                                                ...
                                                )
    

    我的风格还有其他的方便:

    1.可以添加评论:

    person = (
        models
        .UzbekistaniCitizen
        .objects
        .filter(occupation__income__taxable__gte=40000)  # your comment
        .exclude(face__eyes__color=blue)
        .order_by('height')  # 2016-10-11 add
        .select_related('siblings', 'children')
    )
    

    2.调试简单,可以轻松注释一些条件

    下面的代码可以正常工作。这在调试时非常有用,您可以逐行注释条件,而不是删除它并重做。

    person = (
        models
        .UzbekistaniCitizen
        .objects
        # .filter(occupation__income__taxable__gte=40000)
        .exclude(face__eyes__color=blue)
        # .order_by('height')
        .select_related('siblings', 'children')
    )
    

    【讨论】:

    • 最重要的是漂亮。 :)
    • 在我看来,这是一种比其他风格更好的风格。每行有任意数量的空白以保持排列整齐,这让我的眼睛更难以追踪,因为它可以变化很大。
    【解决方案3】:

    我不确定您是否出于说明目的这样做,但根据您的示例,删除对filter 的所有额外调用,只保留一个filter。当filter 有很多参数时,我也倾向于使用可以更自然地跨行分布的字典:

    person = UzbekistaniCitizen.objects.filter(**{
        'hair__color': 'brown',
        'eye__color': 'blue',
        'height__gt': 56,
        'age__lte': 30,
        'job__income__taxable__gt': 40000,
    }).select_related()
    

    FWIW:如果您需要动态修改filter 的参数,这也是一种方便的方法。只需创建一个参数字典,您就可以根据代码中的逻辑追加/更改/删除字典中的项目。然后,你终于将它用于filterMyModel.objects.filter(**my_dict)

    【讨论】:

    • 我不知道你能做到这一点 - 非常有用!
    • 从来没有用过这个!确实非常有用。我投了赞成票,尽管它不再回答问题了。
    【解决方案4】:

    首先映入我眼帘的是,在这种情况下,更常见的是导入类,而不是模块:

    from models import UzbekistaniCitizen
    
    person = UzbekistanCitizen.objects ...
    

    根据您是否经常使用这种过滤,您可以考虑制作自己的自定义model manager,使其采用以下形式:

    #uses myfilter
    person = UzbekistaniCitizen.objects.myfilter(hair__color=brown,
                                                eye__color= blue,
                                                height__gt= 56,
                                                ...
                                                ...
                                                )
    

    或任何其他对您来说可能更方便的东西。

    注意:修改后,使用管理员仍然适用。不必使用 myfilter 方法来模拟过滤器功能,使用管理器可以做更多事情:

    person = UzbekistaniCitizen.males.hair("brown").eyes("blue").income(50000)
    

    这在很大程度上取决于您计划如何使用它,我不会为了缩短查询而制作自定义管理器。

    在您上面提到的两个选项之间,我更喜欢变体 #1。我个人认为它更具可读性,一看就知道发生了什么。 #2 对很多人都有帮助,我的眼睛必须做更多的工作才能找到被调用的相关方法以了解实际发生的情况。

    django 在examples 中使用了变体编号#3:

    Entry.objects.filter(
         headline__startswith='What'
    ).exclude(
         pub_date__gte=datetime.now()
    ).filter(
         pub_date__gte=datetime(2005, 1, 1)
    )
    

    虽然 #3 符合 PEP 8...

    包装长行的首选方法是使用 Python 的隐含 圆括号、方括号和大括号内的行继续。长线可以 通过将表达式括在括号中来分隔多行。这些 应该优先使用反斜杠来续行。

    ...我个人不喜欢在 python 中使用那种挂括号,但随着风格的决定:使用你觉得更舒服的东西,只要它可读且一致。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-24
    • 2018-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-22
    相关资源
    最近更新 更多