Стиль Django: длинные запросы?

У меня есть довольно длинные (~ 150 символов) django-запросы. Какой предпочтительный способ разделить их на несколько строк?

Например (нет, не мой настоящий код):

Изменить: изменил пример, потому что люди были сосредоточены на повторении фильтра, а не на длине запроса:

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

Вот два способа, о которых я могу думать:

  • Использовать обратную косую черту как разрывы строк:

    person = models.UzbekistaniCitizen.objects.\
                              filter(occupation__income__taxable__gte=40000).\
                              exclude(face__eyes__color=blue).\
                              order_by('height').\
                              select_related('siblings', 'children')
    
  • Повторно примените фильтр в новых строках:

    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')
    

Ответ 1

Первое, что появляется на моих глазах, это то, что в этом случае чаще всего импортируется класс, а не модуль:

from models import UzbekistaniCitizen

person = UzbekistanCitizen.objects ...

В зависимости от того, используете ли вы такую ​​фильтрацию очень часто, вы можете подумать о создании своего собственного менеджера моделей, чтобы он выполнял следующие форма:

#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 просто способ для многих людей, и мой взгляд должен сделать немного больше работы, чтобы найти соответствующие методы, вызываемые, чтобы знать, что на самом деле происходит.

Существует вариант номер 3, который django использует сам в :

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, но по мере того, как принимаются решения по стилю: используйте то, с чем вам комфортнее, до тех пор, пока оно читаемо и непротиворечиво.

Ответ 2

Вы можете использовать круглые скобки вокруг всех rhs для продолжения предполагаемого продолжения строки:

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. Просто создайте словарь аргументов, и вы можете добавлять/изменять/удалять элементы в словаре в соответствии с логикой вашего кода. Затем вы, наконец, используете его для filter: MyModel.objects.filter(**my_dict)

Ответ 4

У меня красивый стиль

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

В этом стиле наиболее удобным является то, что вам не нужно отступать вручную, каждый отступ строки имеет несколько пробелов.

Недостаток ниже: 1. Если вы переименуете человека с переменной, вам нужно отрегулировать отступ вручную. 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')
)