Автозаполнение PyCharm не работает для контекстных переменных в шаблонах Django

Обычно автозаполнение (завершение кода) в PyCharm работает для контекстных переменных в шаблонах Django. Например, если контекст - это {"question": question}, где question - это экземпляр модели Question, PyCharm будет предлагать предложения автозаполнения, когда я начну набирать {{ question. }}, например, так:

screenshot of autocomplete working for a context variable in a Django template

Однако в моем текущем проекте Django автозаполнение PyCharm не работает для контекстных переменных в шаблонах Django. Даже нажатие Ctrl + Space не приводит к появлению предложений по завершению кода:

autocomplete failure in Django

Мне кажется, что в PyCharm для Django у меня все настроено как обычно для этого проекта, хотя я могу ошибаться. Это более крупный проект, поэтому я подозреваю, что причиной проблемы может быть что-то в структуре самого проекта.

Другие удобные функции все еще работают в шаблонах Django, например, сокращения Эммета, автозакрытие {{ и {% и т.д.

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

models/
  __init__.py
  model_a.py
  model_b.py
  model_c.py

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

Это касается PyCharm Professional 2023.3.3, хотя я только что обновился до 2024.2.3 и до сих пор испытываю ту же проблему.

Может ли кто-нибудь подсказать причины, по которым автозаполнение PyCharm не работает для контекстных переменных в шаблонах Django?

После некоторых проб и ошибок у меня работает завершение кода в моем проекте.

Вот что я выяснил:

Завершение кода PyCharm для контекстных переменных в шаблонах Django работает при следующих условиях:

  1. При использовании render() в соответствующем представлении
  2. При передаче имени шаблона в качестве строкового литерала в функцию render()

Насколько я могу судить, он не будет работать при использовании TemplateResponse() или HttpResponse() (вместе с модулем django.template.loader) вместо render(). Он также не будет работать, если путь шаблона передается в render() как переменная, а не как строковый литерал.

Например, завершение кода работает, когда представление написано так:

def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, "polls/detail.html", {"question": question})

Также можно передать context в качестве переменной, так что это тоже работает:

def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    context = {"question": question}
    return render(request, "polls/detail.html", context)

Однако завершение кода не удается, если представление написано любым из следующих способов:

Например, при передаче template_name в качестве переменной в render(), а не как строкового литерала:

def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    template_name = "polls/detail.html"
    return render(request, template_name, {"question": question})

, например, при использовании TemplateResponse() вместо render():

def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return TemplateResponse(request, "polls/detail.html", {"question": question})

Например, при использовании HttpResponse() следующим образом:

def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    template = loader.get_template('polls/detail.html')
    return HttpResponse(template.render({"question": question}, request))

Но почему?

Я предполагаю, что сбой завершения кода при использовании TemplateResponse() может быть связан с тем, как он реализует отложенный рендеринг. Возможно, сбой при использовании HttpResponse() (вместе с модулем django.template.loader) происходит по аналогичным причинам.

Я не уверен, почему завершение кода не работает, если template_name не передается непосредственно в render в виде строкового литерала. Кажется, что статический анализ кода должен быть в состоянии вычислить его, если он передается как переменная, которая определена с помощью строкового литерала в том же представлении.

Кавеаты

Если у вас есть хотя бы два вида, использующих один и тот же шаблон, следует обратить внимание на несколько моментов:

  1. Завершение кода будет работать, даже если только одно из представлений использует render() (а также использует строковый литерал для template_name внутри render()). Это сбивает с толку, потому что другие представления могут использовать, например, TemplateResponse(), и завершение кода контекстных переменных все равно будет работать правильно в соответствующем шаблоне.

  2. Если представления, использующие один и тот же шаблон, имеют разные контекстные переменные, PyCharm предложит завершить код всех из них в шаблоне. Это может вызвать проблемы, например, если одно из представлений передает переменную error_message внутри своей context, а другое представление - нет. PyCharm предложит автозаполнить переменную error_message в шаблоне, не предупредив, что некоторые представления не передают эту переменную в context.

Эпилог

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

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

Вернуться на верх