Flask zgłasza błąd TemplateNotFound, mimo że plik szablonu istnieje

111

Próbuję wyrenderować plik home.html. Plik istnieje w moim projekcie, ale ciągle się jinja2.exceptions.TemplateNotFound: home.htmlpojawia, gdy próbuję go wyrenderować. Dlaczego Flask nie może znaleźć mojego szablonu?

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def home():
    return render_template('home.html')
/myproject
    app.py
    home.html
Srdan Ristic
źródło

Odpowiedzi:

222

Musisz utworzyć pliki szablonów w prawidłowej lokalizacji; w templatespodkatalogu obok modułu Pythona.

Błąd wskazuje, że home.htmlw templates/katalogu nie ma pliku . Upewnij się, że utworzyłeś ten katalog w tym samym katalogu co moduł Pythona i że faktycznie umieściłeś home.htmlplik w tym podkatalogu. Jeśli Twoja aplikacja jest pakietem, folder szablonów powinien zostać utworzony wewnątrz pakietu.

myproject/
    app.py
    templates/
        home.html
myproject/
    mypackage/
        __init__.py
        templates/
            home.html

Alternatywnie, jeśli nadałeś folderowi szablonów inną templatesnazwę niż i nie chcesz zmieniać jego nazwy na domyślną, możesz powiedzieć Flask, aby używał tego innego katalogu.

app = Flask(__name__, template_folder='template')  # still relative to module

Możesz poprosić Flask o wyjaśnienie, w jaki sposób próbował znaleźć dany szablon, ustawiając EXPLAIN_TEMPLATE_LOADINGopcję na True. Dla każdego załadowanego szablonu otrzymasz raport zarejestrowany w Kolbieapp.logger na poziomie INFO.

Tak to wygląda, gdy wyszukiwanie się powiedzie; w tym przykładzie foo/bar.htmlszablon rozszerza base.htmlszablon, więc są dwa wyszukiwania:

[2019-06-15 16:03:39,197] INFO in debughelpers: Locating template "foo/bar.html":
    1: trying loader of application "flaskpackagename"
       class: jinja2.loaders.FileSystemLoader
       encoding: 'utf-8'
       followlinks: False
       searchpath:
         - /.../project/flaskpackagename/templates
       -> found ('/.../project/flaskpackagename/templates/foo/bar.html')
[2019-06-15 16:03:39,203] INFO in debughelpers: Locating template "base.html":
    1: trying loader of application "flaskpackagename"
       class: jinja2.loaders.FileSystemLoader
       encoding: 'utf-8'
       followlinks: False
       searchpath:
         - /.../project/flaskpackagename/templates
       -> found ('/.../project/flaskpackagename/templates/base.html')

Schematy mogą również rejestrować własne katalogi szablonów , ale nie jest to wymagane, jeśli używasz planów, aby ułatwić podzielenie większego projektu na jednostki logiczne. Główny katalog szablonów aplikacji Flask jest zawsze przeszukiwany jako pierwszy, nawet jeśli używasz dodatkowych ścieżek na schemat.

Martijn Pieters
źródło
2
EXPLAIN_TEMPLATE_LOADING jest bardzo przydatne do debugowania problemów ze ścieżkami wokół szablonów. Ponadto, jeśli używasz schematów, upewnij się, że ustawiłeś template_folderścieżkę dla planu .
Justin Krause
1
@JustinKrause: dzięki za to, EXPLAIN_TEMPLATE_LOADINGzostało dodane po tym, jak ta odpowiedź została wstępnie napisana.
Martijn Pieters
2
Wygląda na to, że moja lokalna kolba (w systemie Windows) może znaleźć szablony w środku ./Templates/index.html, ale kiedy wdrażam na heroku (myślę, że to ten sam Python, te same wersje bibliotek, w tym ta sama wersja Flask; ale heroku to Unix); i rzuca TemplateNotFoundbłąd; po zmianie nazwy folderu git mv Templates/index.html templates/index.htmldziałały zarówno wersje lokalne (Windows), jak i heroku (Unix)
The Red Pea
1
@TheRedPea tak, ponieważ system plików Windows składa się tak, że Templates== templates. Ale Heroku działa pod Linuksem, z systemem plików uwzględniającym wielkość liter.
Martijn Pieters
13

Myślę, że Flask domyślnie używa szablonów katalogów. Więc twój kod powinien wyglądać tak, jakby to był twój hello.py

from flask import Flask,render_template

app=Flask(__name__,template_folder='template')


@app.route("/")
def home():
    return render_template('home.html')

@app.route("/about/")
def about():
    return render_template('about.html')

if __name__=="__main__":
    app.run(debug=True)

I jak struktura przestrzeni roboczej

project/
    hello.py        
    template/
         home.html
         about.html    
    static/
           js/
             main.js
           css/
               main.css

musisz również utworzyć dwa pliki html o nazwach home.html i about.html i umieścić je w folderze szablonów.

Akshay Karande
źródło
8

(Należy pamiętać, że powyższa zaakceptowana odpowiedź podana dla struktury pliku / projektu jest absolutnie poprawna.)

Również..

Oprócz poprawnego ustawienia struktury plików projektu, musimy powiedzieć flaskowi, aby szukał w odpowiednim poziomie hierarchii katalogów.

na przykład..

    app = Flask(__name__, template_folder='../templates')
    app = Flask(__name__, template_folder='../templates', static_folder='../static')

Rozpoczynanie od ../powoduje przejście o jeden katalog wstecz i rozpoczęcie w tym miejscu.

Rozpoczynanie od ../../przenosi dwa katalogi wstecz i zaczyna tam (i tak dalej ...).

Mam nadzieję że to pomoże

Żaden
źródło
5

Nie wiem dlaczego, ale zamiast tego musiałem użyć następującej struktury folderów. Umieszczam „szablony” o jeden poziom wyżej.

project/
    app/
        hello.py
        static/
            main.css
    templates/
        home.html
    venv/

To prawdopodobnie wskazuje na błędną konfigurację w innym miejscu, ale nie mogłem dowiedzieć się, co to było i to zadziałało.

François Breton
źródło
3

Sprawdź to:

  1. plik szablonu ma odpowiednią nazwę
  2. plik szablonu znajduje się w podkatalogu o nazwie templates
  3. nazwa, do której przekazujesz, render_templatejest określana względem katalogu szablonów ( index.htmlznajdowałaby się bezpośrednio w katalogu szablonów, auth/login.htmlw katalogu auth w katalogu szablonów).
  4. albo nie masz podkatalogu o takiej samej nazwie jak Twoja aplikacja lub katalog szablonów znajduje się w tym podkatalogu.

Jeśli to nie zadziała, włącz debugowanie ( app.debug = True), co może pomóc dowiedzieć się, co jest nie tak.

Eric
źródło
3

Jeśli uruchamiasz kod z zainstalowanego pakietu, upewnij się, że pliki szablonów znajdują się w katalogu <python root>/lib/site-packages/your-package/templates.


Trochę szczegółów:

W moim przypadku próbowałem uruchomić przykłady projektu flask_simple_ui i jinjazawsze mówiłem

jinja2.exceptions.TemplateNotFound: form.html

Sztuczka polegała na tym, że przykładowy program importował zainstalowany pakiet flask_simple_ui. A ninjaużywanie z wnętrza tego pakietu oznacza używanie jako katalogu głównego do wyszukiwania ścieżki pakietu, w moim przypadku ...python/lib/site-packages/flask_simple_ui, zamiast tego, os.getcwd() czego można by się spodziewać.

Niestety, setup.pyma błąd i nie kopiuje żadnych plików html, w tym brakujących form.html. Po rozwiązaniu setup.pyproblem z TemplateNotFound zniknął.

Mam nadzieję, że to komuś pomoże.

Yuriy Pozniak
źródło
2

Miałem ten sam błąd, okazało się, że jedyną rzeczą, jaką zrobiłem źle, było nazwanie folderu „szablony”, a „szablon” bez „s”. Po zmianie, że działało dobrze, nie wiem, dlaczego to jest coś, ale tak jest.

Shubham Khaire
źródło
2

Gdy używana jest funkcja render_template (), próbuje ona wyszukać szablon w folderze o nazwie templates i zgłasza błąd jinja2.exceptions.TemplateNotFound, gdy:

  1. plik html nie istnieje lub
  2. gdy folder szablonów nie istnieje

Rozwiązać problem :

utwórz folder z szablonami nazw w tym samym katalogu, w którym znajduje się plik Pythona i umieść utworzony plik html w folderze szablonów.

Atal Kumar
źródło
1

Musisz umieścić wszystkie swoje .htmlpliki w folderze szablonów obok modułu Pythona. A jeśli są jakieś obrazy, których używasz w swoich plikach html, musisz umieścić wszystkie swoje pliki w folderze o nazwie static

W poniższej strukturze

project/
    hello.py
    static/
        image.jpg
        style.css
    templates/
        homepage.html
    virtual/
        filename.json
Madhusudan chowdary
źródło
1

Inną alternatywą jest ustawienie, root_pathktóre rozwiązuje problem zarówno w przypadku szablonów, jak i folderów statycznych.

root_path = Path(sys.executable).parent if getattr(sys, 'frozen', False) else Path(__file__).parent
app = Flask(__name__.split('.')[0], root_path=root_path)

Jeśli renderujesz szablony bezpośrednio przez Jinja2, piszesz:

ENV = jinja2.Environment(loader=jinja2.FileSystemLoader(str(root_path / 'templates')))
template = ENV.get_template(your_template_name)
Maks
źródło
0

Mój problem polegał na tym, że plik, do którego odwoływałem się od wewnątrz, home.htmlbył a .j2zamiast a .html, a kiedy go zmieniłem, jinja mogła go odczytać.

Głupi błąd, ale może komuś pomóc.

Still_learning
źródło