เทมเพลต django: รวมและขยาย


109

ฉันต้องการให้เนื้อหาเดียวกันภายใน 2 ไฟล์พื้นฐานที่แตกต่างกัน

ฉันกำลังพยายามทำสิ่งนี้:

page1.html:

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

page2.html:

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

ปัญหาคือดูเหมือนว่าฉันใช้ทั้งขยายและรวมไม่ได้ มีวิธีทำบ้างไหม และถ้าไม่ฉันจะทำสิ่งที่กล่าวมาข้างต้นให้สำเร็จได้อย่างไร?

commondata.html แทนที่บล็อกที่ระบุทั้ง base1.html และ base2.html

จุดประสงค์นี้คือเพื่อให้หน้าเดียวกันทั้งในรูปแบบ pdf และ html ซึ่งการจัดรูปแบบจะแตกต่างกันเล็กน้อย แม้ว่าคำถามข้างต้นจะทำให้สิ่งที่ฉันพยายามทำนั้นง่ายขึ้นหากฉันได้รับคำตอบว่ามันจะช่วยแก้ปัญหาของฉันได้

คำตอบ:


110

เมื่อคุณใช้แท็กแม่แบบขยายคุณกำลังบอกว่าแม่แบบปัจจุบันขยายอีกอันหนึ่งนั่นคือแม่แบบลูกขึ้นอยู่กับแม่แบบแม่ Django จะดูแม่แบบลูกของคุณและใช้เนื้อหาเพื่อเติมข้อมูลแม่

ทุกสิ่งที่คุณต้องการใช้ในแม่แบบลูกควรอยู่ในบล็อกซึ่ง Django ใช้เพื่อเติมข้อมูลแม่ หากคุณต้องการใช้คำสั่ง include ในเทมเพลตลูกนั้นคุณต้องใส่ไว้ในบล็อกเพื่อให้ Django เข้าใจได้ มิฉะนั้นมันก็ไม่สมเหตุสมผลและ Django ก็ไม่รู้ว่าจะทำอย่างไรกับมัน

เอกสาร Django มีตัวอย่างที่ดีจริง ๆ ในการใช้บล็อกเพื่อแทนที่บล็อกในเทมเพลตหลัก

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


1
commondata.html ของฉันมีบล็อกที่กำหนดไว้ในนั้น แต่มันไม่ได้แทนที่บล็อกของเทมพัลต์หลัก ... หากแทนที่จะทำการรวมฉันเขียนข้อมูลที่แน่นอนสองครั้งในทั้ง page1.html และ page2.html แน่นอนว่ามันใช้งานได้ แต่ฉันต้องการแยกความธรรมดานั้นออกเป็น commondata.html
Net Citizen

ดูเหมือนจะได้ผลฉันจำได้ว่าลองทำสิ่งนี้ แต่ฉันต้องมีการพิมพ์ผิดหรือบางอย่างในเวลานั้นทำให้ไม่สามารถใช้งานได้
Net Citizen

1
ดูคำตอบของฉันด้านล่างว่าเหตุใดฉันจึงไม่ได้ผลในครั้งแรกฉันจะปล่อยให้คุณมีคำตอบที่ยอมรับแม้ว่าคุณจะตอบคำถามที่ฉันถามถูกต้อง
Net Citizen

80

จาก Django docs:

แท็กรวมควรถือเป็นการใช้งาน "แสดงเทมเพลตย่อยนี้และรวม HTML" ไม่ใช่ "แยกวิเคราะห์เทมเพลตย่อยนี้และรวมเนื้อหาราวกับว่าเป็นส่วนหนึ่งของพาเรนต์" ซึ่งหมายความว่าไม่มีสถานะที่ใช้ร่วมกันระหว่างเทมเพลตที่รวมอยู่ - แต่ละเทมเพลตเป็นกระบวนการแสดงผลที่เป็นอิสระอย่างสมบูรณ์

ดังนั้น Django จึงไม่จับบล็อกใด ๆ จาก commondata.html ของคุณและไม่รู้ว่าจะทำอย่างไรกับ html นอกบล็อกที่แสดงผล


32

สิ่งนี้น่าจะเป็นเคล็ดลับสำหรับคุณ: ใส่แท็กรวมไว้ในส่วนบล็อก

page1.html:

{% extends "base1.html" %}

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

page2.html:

{% extends "base2.html" %}

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

1
สมบูรณ์แบบ. ใช้ได้ผลสำหรับฉัน
Trupti M Panchal

13

ข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุที่ไม่ได้ผลสำหรับฉันในกรณีที่ช่วยเหลือผู้คนในอนาคต:

สาเหตุที่ใช้ไม่ได้คือ {% include%} ใน django ไม่ชอบอักขระพิเศษเช่นเครื่องหมายวรรคตอนแบบแฟนซี ข้อมูลเทมเพลตที่ฉันพยายามรวมถูกวางจาก word ฉันต้องลบอักขระพิเศษเหล่านี้ทั้งหมดด้วยตนเองจากนั้นจึงรวมสำเร็จ


3

คุณไม่สามารถดึงบล็อกจากไฟล์ที่รวมมาไว้ในเทมเพลตลูกเพื่อลบล้างบล็อกของแม่แบบหลักได้ อย่างไรก็ตามคุณสามารถระบุพาเรนต์ในตัวแปรและระบุเทมเพลตพื้นฐานในบริบทได้

จากเอกสารประกอบ :

{% expands variable%} ใช้ค่าของตัวแปร หากตัวแปรประเมินเป็นสตริง Django จะใช้สตริงนั้นเป็นชื่อของเทมเพลตหลัก หากตัวแปรประเมินเป็นวัตถุแม่แบบ Django จะใช้วัตถุนั้นเป็นแม่แบบหลัก

แทนที่จะแยก "page1.html" และ "page2.html" ให้วาง{% extends base_template %}ที่ด้านบนของ "commondata.html" จากนั้นในมุมมองของคุณให้กำหนดbase_templateเป็น "base1.html" หรือ "base2.html"


2

เพิ่มเพื่ออ้างอิงถึงคนในอนาคตที่พบสิ่งนี้ผ่านทาง Google: คุณอาจต้องการดูแท็ก {% Overextend%} ที่ไลบรารีชั้นลอยจัดเตรียมไว้สำหรับกรณีเช่นนี้


1

แก้ไข 10 ธันวาคม 2558 : ตามที่ระบุไว้ในความคิดเห็นssiเลิกใช้งานตั้งแต่เวอร์ชัน 1.8 ตามเอกสาร:

แท็กนี้เลิกใช้งานแล้วและจะถูกลบออกใน Django 1.10 ใช้แท็กรวมแทน


ในความคิดของฉันคำตอบที่ถูกต้อง (ดีที่สุด) สำหรับคำถามนี้คือคำตอบจากpodshumokเนื่องจากอธิบายว่าเหตุใดพฤติกรรมของ include เมื่อใช้ร่วมกับการสืบทอด

แต่ผมรู้สึกประหลาดใจบ้างว่าไม่มีใครกล่าวถึงSSIแท็กให้โดยระบบ templating Django ซึ่งถูกออกแบบมาโดยเฉพาะสำหรับอินไลน์รวมทั้งชิ้นส่วนภายนอกของข้อความ ในที่นี้อินไลน์หมายความว่าข้อความภายนอกจะไม่ถูกตีความแยกวิเคราะห์หรือสอดแทรก แต่เพียงแค่ "คัดลอก" ภายในเทมเพลตการโทร

โปรดดูเอกสารสำหรับรายละเอียดเพิ่มเติม (อย่าลืมตรวจสอบ Django เวอร์ชันที่เหมาะสมของคุณในตัวเลือกที่ส่วนล่างขวาของหน้า)

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

จากเอกสารประกอบ:

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

ระวังผลกระทบด้านความปลอดภัยของเทคนิคนี้และข้อกำหนด ALLOWED_INCLUDE_ROOTS ที่จำเป็นซึ่งต้องเพิ่มในไฟล์การตั้งค่าของคุณ


1
หมายเหตุ ณ วันที่ 1.8 ssi ได้ถูกเลิกใช้งานแล้วเพื่อสนับสนุนการรวม https://docs.djangoproject.com/th/1.8/ref/templates/builtins/#std:templatetag-include
Tim S.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.