Django - Советы, позволяющие избежать повторения кода в представлениях

StackOverflow https://stackoverflow.com/questions/2482525

  •  21-09-2019
  •  | 
  •  

Вопрос

Я перехожу от фона PHP к разработке Django с помощью Python, в основном ради решения MVC (или MVT), который, по моему мнению, имеет наибольший смысл, хотя в этом шаблоне я начал замечать много повторяющегося кода в моих представлениях.

Например, при входе в систему у меня есть информация о пользователе, которую я хотел бы видеть на каждой странице, хотя при использовании render_to_response и в каждом представлении это обязательно, я должен получить информацию и передать ее функции render_to_response.

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

Заранее благодарю.

Это было полезно?

Решение

Лично я большой поклонник декораторов, которые являются функцией Python, не характерной для Django.Декораторы являются идеальным синтаксическим дополнением к функциям более высокого порядка, и они особенно полезны для уменьшения шаблонности в представлениях - вы можете быстро определить обобщенную функцию-оболочку, в которую вы можете поместить повторяющийся код для легкого повторного использования и удобного универсального рефакторинга.

Вероятно, проще показать вам, чем объяснять, как они работают.Вот упрощенный пример просмотра:

def listpage(request):
    return HttpResponse(render_to_string("itemlist.html", {
        "items": Item.objects.filter(visible=True).order_by("-modifydate")
    }))

def itemlist_tags(request, tags):
    return HttpResponse(render_to_string("itemlist.html", {
        "items": Item.objects.tagged(name=tags).filter(visible=True).order_by("-modifydate"),
    }))

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

def listpage(request):
    if not request.user.is_authenticated():
        return f(request, *args, **kwargs)
    else:
        return HttpResponse(render_to_string("itemlist.html", {
            "items": Item.objects.filter(visible=True).order_by("-modifydate")
        }))

def itemlist_tags(request, tags):
    if not request.user.is_authenticated():
        return f(request, *args, **kwargs)
    else:
        return HttpResponse(render_to_string("itemlist.html", {
            "items": Item.objects.tagged(name=tags).filter(visible=True).order_by("-modifydate"),
        }))

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

из декоратора импортировать декоратор

@decorator
def loginrequired(f, request, *args, **kwargs):
    if request.user.is_authenticated():
        return f(request, *args, **kwargs)
    else:
        return HttpResponseRedirect("/")

@loginrequired
def listpage(request):
    return HttpResponse(render_to_string("itemlist.html", {
        "items": Item.objects.filter(visible=True).order_by("-modifydate")
    }))

    @loginrequired
def itemlist_tags(request, tags):
    return HttpResponse(render_to_string("itemlist.html", {
        "items": Item.objects.tagged(name=tags).filter(visible=True).order_by("-modifydate"),
    }))

@loginrequired
def another_such_function(request):
    (...)

@loginrequired
def and_again(request):
    (...)

Что происходит, так это то, что функция декоратора выполняется во время определения функции.'f' в моем примере - это объект, представляющий функцию, к которой применяется декоратор, которой вы можете манипулировать бесконечными способами.

Для этого требуется библиотека декораторов, который является бесплатным на PyPI, как и многие другие полезные функции python, которые вы найдете.

Вам не нужна библиотека this для написания функций декоратора, но это полезно, особенно в начале.Они могут сделать намного больше - любой вызываемый объект может быть декоратором;вы можете украсить методы класса и перехватить self переменная;декораторы могут быть скованы цепью, вот так:

@second
@first
def originalfunction(*args):
    (...)

Я оставлю исследование того, что вы можете сделать с помощью такого простого управления функциями высшего порядка, для вас, если эта идея разожжет ваш аппетит.У меня есть еще много примеров для вас или любых других любопытных новых поклонников python.Удачи.

Другие советы

Инкапсулируйте общий код в функцию и вызывайте его из разных представлений.Звучит тривиально, но это решение для 99% таких потребностей.

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

Существует два основных способа абстрагирования общего контента.

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

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

Кроме того, не забывайте о общие представления!В 90% случаев вы можете обернуть object_list или object_detail и сохранить себе некоторый код.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top