szablony django: dołączanie i rozszerzanie

108

Chciałbym zapewnić tę samą zawartość w 2 różnych plikach podstawowych.

Więc próbuję to zrobić:

page1.html:

{% extends "base1.html" %}
{% include "commondata.html" %}

page2.html:

{% extends "base2.html" %} 
{% include "commondata.html" %}

Problem polega na tym, że nie mogę używać zarówno rozszerzeń, jak i dołączania. Czy jest jakiś sposób, aby to zrobić? A jeśli nie, jak mogę to osiągnąć?

commondata.html zastępuje blok określony zarówno w base1.html, jak i base2.html

Ma to na celu udostępnienie tej samej strony w formacie pdf i html, gdzie formatowanie jest nieco inne. Powyższe pytanie upraszcza jednak to, co próbuję zrobić, więc jeśli mogę uzyskać odpowiedź, że rozwiąże to mój problem.

Net Citizen
źródło

Odpowiedzi:

110

Kiedy używasz znacznika extends template, mówisz, że bieżący szablon rozszerza inny - że jest to szablon podrzędny zależny od szablonu nadrzędnego. Django spojrzy na twój szablon potomny i użyje jego zawartości do wypełnienia rodzica.

Wszystko, czego chcesz użyć w szablonie potomnym, powinno znajdować się w blokach, których Django używa do zapełnienia rodzica. Jeśli chcesz użyć instrukcji include w tym szablonie potomnym, musisz umieścić ją w bloku, aby Django nadało jej sens. W przeciwnym razie nie ma to sensu, a Django nie wie, co z tym zrobić.

Dokumentacja Django zawiera kilka naprawdę dobrych przykładów użycia bloków do zastępowania bloków w szablonie nadrzędnym.

https://docs.djangoproject.com/en/dev/ref/templates/language/#template-inheritance

Matt Howell
źródło
1
mój commondata.html ma zdefiniowany blok. Ale to nie jest zastępowanie bloku macierzystego tempalte ... Jeśli zamiast wykonać dołączanie, zapiszę dokładne dane dwa razy w obu stronach: page1.html i page2.html, to oczywiście zadziała. Ale chcę wyliczyć tę podobieństwo w commondata.html.
Net Citizen
Wydaje się, że działa, pamiętam, że próbowałem tego, ale musiałem mieć wtedy literówkę lub coś, co spowodowało, że nie działa.
Net Citizen
1
zobacz moją odpowiedź poniżej, aby dowiedzieć się, dlaczego nie zadziałała w moim przypadku za pierwszym razem, ale zostawię ci zaakceptowaną odpowiedź, ponieważ odpowiedziałeś poprawnie na pytanie, które zadałem.
Net Citizen
80

Z dokumentów Django:

Znacznik dołączania powinien być traktowany jako implementacja „wyrenderuj ten szablon podrzędny i dołącz kod HTML”, a nie „przeanalizuj ten szablon podrzędny i dołącz jego zawartość, jakby była częścią elementu nadrzędnego”. Oznacza to, że nie ma współdzielonego stanu między dołączonymi szablonami - każdy dołączenie jest całkowicie niezależnym procesem renderowania.

Więc Django nie pobiera żadnych bloków z twojego commondata.html i nie wie, co zrobić z wyrenderowanymi blokami HTML.

podshumok
źródło
32

To powinno załatwić sprawę: umieść tag include w sekcji bloku.

page1.html:

{% extends "base1.html" %}

{% block foo %}
   {% include "commondata.html" %}
{% endblock %}

page2.html:

{% extends "base2.html" %}

{% block bar %}
   {% include "commondata.html" %}
{% endblock %}
Pavel Černý
źródło
1
Idealny. Pracuje dla mnie.
Trupti M Panchal
13

Więcej informacji o tym, dlaczego to nie działa dla mnie na wypadek, gdyby pomogło przyszłym ludziom:

Powodem, dla którego to nie działało, jest to, że {% include%} w django nie lubi znaków specjalnych, takich jak fantazyjny apostrof. Dane szablonu, które próbowałem dołączyć, zostały wklejone z programu Word. Musiałem ręcznie usunąć wszystkie te znaki specjalne, a następnie zostały pomyślnie dołączone.

Net Citizen
źródło
3

Nie możesz przeciągać bloków z dołączonego pliku do szablonu podrzędnego, aby nadpisać bloki szablonu nadrzędnego. Można jednak określić rodzica w zmiennej i określić szablon podstawowy w kontekście.

Z dokumentacji :

{% rozszerza zmienną%} używa wartości zmiennej. Jeśli zmienna ma wartość łańcucha, Django użyje tego ciągu jako nazwy szablonu nadrzędnego. Jeśli zmienna ma wartość obiektu szablonu, Django użyje tego obiektu jako szablonu nadrzędnego.

Zamiast oddzielnych „page1.html” i „page2.html”, umieść {% extends base_template %}na górze „commondata.html”. Następnie w swoim widoku określ base_templatejako „podstawa1.html” lub „podstawa2.html”.

szmergiel
źródło
2

Dodano w celu odniesienia do przyszłych osób, które znajdą to w Google: W takich przypadkach możesz zajrzeć do tagu {% overextend%} dostarczonego przez bibliotekę mezzanine.

Przetrząsać
źródło
1

Edycja 10 grudnia 2015 r . : Jak wskazano w komentarzach, ssi jest przestarzały od wersji 1.8. Zgodnie z dokumentacją:

Ten tag jest przestarzały i zostanie usunięty w Django 1.10. Zamiast tego użyj tagu include.


Moim zdaniem właściwą (najlepszą) odpowiedzią na to pytanie jest ta z podshumok , ponieważ wyjaśnia, dlaczego zachowanie include, gdy jest używane wraz z dziedziczeniem.

Byłem jednak nieco zaskoczony, że nikt nie wspomniał o tagu ssi dostarczonym przez system szablonów Django, który jest specjalnie zaprojektowany do umieszczania w wierszu zawierającego zewnętrzny fragment tekstu . W tym przypadku inline oznacza, że ​​tekst zewnętrzny nie będzie interpretowany, analizowany ani interpolowany, ale po prostu „kopiowany” wewnątrz szablonu wywołującego.

Aby uzyskać więcej informacji, zapoznaj się z dokumentacją (sprawdź odpowiednią wersję Django w selektorze w prawej dolnej części strony).

https://docs.djangoproject.com/en/dev/ref/templates/builtins/#ssi

Z dokumentacji:

ssi
Outputs the contents of a given file into the page.
Like a simple include tag, {% ssi %} includes the contents of another file
 which must be specified using an absolute path  in the current page

Uważaj również na konsekwencje tej techniki dla bezpieczeństwa, a także na wymagane definicje ALLOWED_INCLUDE_ROOTS, które należy dodać do plików ustawień.

jose.angel.jimenez
źródło
1
Uwaga: od 1.8, ssi został wycofany na korzyść Include. https://docs.djangoproject.com/en/1.8/ref/templates/builtins/#std:templatetag-include
Tim S.