Джанго шаблон и трюк местных жителей - PullRequest
51 голосов
/ 14 декабря 2009

Книги django дают локальный трюк, чтобы не вводить длинный список параметров в качестве контекстного словаря http://www.djangobook.com/en/2.0/chapter04/

Он рекомендует это для ленивых программистов, но указывает на некоторые накладные расходы, которые могут повлиять на производительность.

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

Ответы [ 8 ]

76 голосов
/ 14 декабря 2009

Мне не нравится повторение - я думаю, что «СУХОЙ», «Не повторяй себя», является ключевым принципом программирования. Как следствие, я действительно использовал locals() в подобных ситуациях. Визуализация шаблона Django - далеко не единственная ситуация такого рода: общий случай - это «функция или оператор, который принимает dict, но не возражает, если в dict есть дополнительные записи». (Например, обычное форматирование строк в Python является еще одним таким случаем).

Тем не менее, существует противоположный принцип: программы должны быть понятны настолько локализованно, насколько это возможно - это помогает в обслуживании и рефакторинге (поскольку это устраняет необходимость изучения других файлов, чтобы проверить, какие рефакторинги приемлемы). Для случая locals() это говорит о том, что все в порядке, если шаблон (или формат строки и т. Д.) Является локальным литералом (редкий случай, когда, вероятно, используется только несколько переменных, и, таким образом, locals() не является огромным выигрышем! -), но проблематично в обычном случае, когда шаблон находится в другом файле.

Таким образом, использование locals() в большинстве случаев серьезно затрудняет рефакторинг. Почти в каждой ситуации в Python локальные переменные и их имена могут быть свободно изменены как часть локального рефакторинга, так как они не имеют "видимого извне" эффекта ... но использование locals() прерывает это - внезапно вы не можете безопасно переименуйте переменную в другое имя, предлагая лучшую ясность, рефакторинг потока кода таким образом, что устраняет необходимость в переменной, и т. д., и т. д., при этом каждый раз не изучая отдельный файл шаблона, чтобы проверить, не нужно ли старое имя ( и, возможно, редактирование файла шаблона, который может быть нетривиальным, например, если он поддерживается на нескольких разных естественных языках для целей i18n / L10n).

Как следствие, в дополнение к вторичной проблеме производительности, существует сильное давление против с использованием locals() в «серьезном», «производственном» коде - коде, который действительно требует длительного обслуживания и Поэтому легко рефакторинг и местность. Поэтому, когда я «программирую так хорошо, как умею», а не «срезаю углы», я осознаю, что мне лучше избегать locals().

Значения, которые вы хотите иметь в контексте, в котором отображается шаблон, не обязательно «естественно» доступны как локальные голые имена, в конце концов; может быть, некоторые или многие из них являются результатами вычислений, элементами из списков или словарей и т.п. В этом случае соблазна «срезать углы» с помощью locals() легче избежать, если вы просто накапливаете эти значения в подходящий словарь, а не присваиваете им локальные голые имена.

Это не самый простой компромисс, потому что два хороших принципа (избегание повторения и хорошее месторасположение) неизбежно сталкиваются - следовательно, хороший вопрос! И не один полностью восприимчивый к острым черным или белым ответам, поэтому я попытался расширить с обеих сторон. В конце концов, я думаю, что это один из тех «стилевых» аспектов, когда команде программистов следует посоветовать принять единообразное руководство по стилю и придерживаться его - по крайней мере, это устраняет необходимость принимать решения снова и снова Со временем возникает проблема, и создается более однородная (и, следовательно, поддерживаемая) база кода. [[Я должен признаться, что этот конкретный момент никогда не рассматривался в руководстве по стилю команд, в которых я был, хотя многие другие это делали! -)]]

27 голосов
/ 14 декабря 2009

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

class MyStruct(object):
     pass

def my_view(request, id):
    c = MyStruct()
    c.customer = ..
    c.invoice = ..
    c.date = ..
    return render_to_response('xxx,html',c.__dict__)
12 голосов
/ 14 декабря 2009

Лично мне это не нравится. Вероятно, нет никаких причин для моих предпочтений, кроме старого изречения Python «Явное лучше, чем неявное». Мне нравится точно знать, что входит в мои шаблоны.

3 голосов
/ 14 декабря 2009

Я использовал его без проблем (пока!).

Я не особенно люблю печатать, поэтому мне это нравится. Код как

'customer' : customer,
'invoice' : invoice,
'date' : date

выглядит просто смешно для меня, и если я смогу избежать этого, я сделаю это. Одна из причин, по которой мне нравится Python, - отсутствие шаблонного кода (хотя на самом деле это не шаблонный шаблон, а аналогичный).

2 голосов
/ 14 декабря 2009

Я думаю, это зависит от того, сколько локальных переменных вы определили в своей функции.

Если оно точно соответствует номеру, который вы хотите вернуть в шаблон, или «дополнительные» переменные представляют собой простые структуры, такие как целые или логические значения, то я думаю, что нет смысла явно возвращать их, поскольку это требует больше работы.

Но, с другой стороны, если в вашем представлении много сложных «вспомогательных» переменных, таких как экземпляры вашей модели, которые вы используете в представлении для генерации данных, которые вы хотите отправить в шаблон, тогда вы можете рассмотреть использовать явные переменные для возврата к шаблону.

1 голос
/ 19 сентября 2016

Чтобы уменьшить беспорядок в views.py при сохранении явного: В controllers.py:

import sys

def auto_context(the_locals=None):
    # Take any variable in the locals() whose name ends with an underscore, and
    # put it in a dictionary with the underscore removed.

    if the_locals is None:
        # We can access the locals of the caller function even if they
        # aren't passed in.
        caller = sys._getframe(1)
        the_locals = caller.f_locals

    return dict([
        (key[:-1], value)
        for (key, value) in the_locals.items()
        if key[-1] == "_"])

В views.py:

from app.controllers import auto_context

def a_view(request): 
    hello_ = "World" # This will go into the context.
    goodnight = "Moon" # This won't.
    return render(request, "template.html", auto_context())

В template.html, используйте {{ hello }}.

Вы вряд ли случайно дадите переменной имя, заканчивающееся подчеркиванием. Таким образом, вы будете точно знать, что входит в шаблон. Используйте auto_context() или эквивалентно auto_context(locals()). Наслаждайтесь!

1 голос
/ 29 марта 2015

Я знаю, что это старая тема ... в настоящее время render_to_response устарела. Вместо этого используйте render без locals (). Обходить всех местных жителей - плохая практика. Вот пример views.py:

from django.shortcuts import render
from django.contrib.auth.decorators import login_required

@login_required
def mybooks(request):
    entries = Book.objects.all()
    return render(request, 'mybooks.html', {'entries': entries})
0 голосов
/ 31 июля 2014

Я согласен с Алексом. Не вижу смысла в создании экземпляра класса (как предложил niels), когда вы можете просто сделать это:

def my_view(request, id):
    customer = ..
    invoice = ..
    date = ..
    return render_to_response('xxx,html', locals())

Если вам нужна производительность, точечный поиск будет медленнее.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...