QWeb Templates¶
QWeb is the primary templating engine used by Odoo2. It is an XML templating engine1 and used mostly to generate HTML fragments and pages.
Template directives are specified as XML attributes prefixed with t-,
for instance t-if for Conditionals, with elements
and other attributes being rendered directly.
To avoid element rendering, a placeholder element <t> is also available,
which executes its directive but doesn't generate any output in and of
itself:
<t t-if="condition">
<p>Test</p>
</t>
منجر میشود به:
<p>Test</p>
if condition is true, but:
<div t-if="condition">
<p>Test</p>
</div>
منجر میشود به:
<div>
<p>Test</p>
</div>
Data output¶
QWeb's output directive out will automatically HTML-escape its input,
limiting XSS risks when displaying user-provided content.
out takes an expression, evaluates it and injects the result in the document:
<p><t t-out="value"/></p>
rendered with the value value set to 42 yields:
<p>42</p>
See خروجی پیشرفته for more advanced topics (e.g. injecting raw HTML, etc...).
Conditionals¶
QWeb has a conditional directive if, which evaluates an expression given
as attribute value:
<div>
<t t-if="condition">
<p>ok</p>
</t>
</div>
The element is rendered if the condition is true:
<div>
<p>ok</p>
</div>
but if the condition is false it is removed from the result:
<div>
</div>
The conditional rendering applies to the bearer of the directive, which does
not have to be <t>:
<div>
<p t-if="condition">ok</p>
</div>
will give the same results as the previous example.
Extra conditional branching directives t-elif and t-else are also
available:
<div>
<p t-if="user.birthday == today()">Happy birthday!</p>
<p t-elif="user.login == 'root'">Welcome master!</p>
<p t-else="">Welcome!</p>
</div>
Loops¶
QWeb has an iteration directive foreach which take an expression returning
the collection to iterate on, and a second parameter t-as providing the
name to use for the "current item" of the iteration:
<t t-foreach="[1, 2, 3]" t-as="i">
<p><t t-out="i"/></p>
</t>
will be rendered as:
<p>1</p>
<p>2</p>
<p>3</p>
Like conditions, foreach applies to the element bearing the directive's
attribute, and
<p t-foreach="[1, 2, 3]" t-as="i">
<t t-out="i"/>
</p>
is equivalent to the previous example.
foreach can iterate on an array (the current item will be the current
value) or a mapping (the current item will be the current key). Iterating on an
integer (equivalent to iterating on an array between 0 inclusive and the
provided integer exclusive) is still supported but deprecated.
In addition to the name passed via t-as, foreach provides a few other
variables for various data points:
هشدار
$as will be replaced by the name passed to t-as
$as_all(deprecated)the object being iterated over
توجه
This variable is only available on JavaScript QWeb, not Python.
$as_valueمقدار تکرار جاری؛ برای فهرستها و اعداد صحیح مشابه
$asاست، اما برای نگاشتها مقدار را فراهم میکند (در حالی که$asکلید را فراهم میکند)$as_indexاندیس تکرار جاری (نخستین آیتم تکرار دارای اندیس ۰ است)
$as_sizeاندازهٔ مجموعه در صورت دسترسپذیری
$as_firstاینکه آیا آیتم جاری اولین آیتم تکرار است (معادل
$as_index == 0)$as_lastاینکه آیا آیتم جاری آخرین آیتم تکرار است (معادل
$as_index + 1 == $as_size)؛ نیازمند در دسترس بودن اندازهٔ مجموعهٔ پیمایششونده است$as_parity(منسوخ)یکی از
"even"یا"odd"؛ زوج یا فرد بودن دور تکرار جاری$as_even(منسوخ)پرچم بولی که نشان میدهد دور تکرار جاری روی اندیسی زوج قرار دارد
$as_odd(منسوخ)پرچم بولی که نشان میدهد دور تکرار جاری روی اندیسی فرد قرار دارد
این متغیرهای اضافی و همهٔ متغیرهای جدید ساختهشده در foreach تنها در محدودهٔ foreach در دسترس هستند. اگر متغیر بیرون از زمینهٔ foreach وجود داشته باشد، مقدار در پایان foreach به زمینهٔ سراسری کپی میشود.
<t t-set="existing_variable" t-value="False"/>
<!-- existing_variable now False -->
<p t-foreach="[1, 2, 3]" t-as="i">
<t t-set="existing_variable" t-value="True"/>
<t t-set="new_variable" t-value="True"/>
<!-- existing_variable and new_variable now True -->
</p>
<!-- existing_variable always True -->
<!-- new_variable undefined -->
attributes¶
QWeb میتواند ویژگیها را بهصورت پویا محاسبه کند و نتیجهٔ محاسبه را روی گرهٔ خروجی قرار دهد. این کار با دستور t-att (ویژگی) انجام میشود که در ۳ شکل مختلف وجود دارد:
t-att-$nameویژگیای با نام
$nameساخته میشود، مقدار ویژگی ارزیابی میشود و نتیجه بهعنوان مقدار ویژگی تنظیم میشود:<div t-att-a="42"/>
will be rendered as:
<div a="42"></div>
t-attf-$nameمشابه قبلی، اما پارامتر یک format string است بهجای صرفاً یک عبارت؛ معمولاً برای ترکیب رشتههای ادبی و غیرادبی (مثلاً کلاسها) مفید است:
<t t-foreach="[1, 2, 3]" t-as="item"> <li t-attf-class="row {{ (item_index % 2 === 0) ? 'even' : 'odd' }}"> <t t-out="item"/> </li> </t>
will be rendered as:
<li class="row even">1</li> <li class="row odd">2</li> <li class="row even">3</li>
نکته
دو نحو معادل برای رشتههای قالببندی وجود دارد:
"plain_text {{code}}"(موسوم به سبک jinja) و"plain_text #{code}"(موسوم به سبک ruby).t-att=mappingاگر پارامتر یک نگاشت باشد، هر جفت (کلید، مقدار) یک ویژگی جدید و مقدارش را تولید میکند:
<div t-att="{'a': 1, 'b': 2}"/>
will be rendered as:
<div a="1" b="2"></div>
t-att=pairاگر پارامتر یک جفت باشد (تاپل یا آرایهٔ ۲ عنصری)، آیتم نخست جفت نام ویژگی است و آیتم دوم مقدار آن:
<div t-att="['a', 'b']"/>
will be rendered as:
<div a="b"></div>
تنظیم متغیرها¶
QWeb امکان ایجاد متغیرها را از درون قالب فراهم میکند، تا یک محاسبه را بهخاطر بسپارد (برای استفادهٔ چندباره)، نامی روشنتر به دادهای بدهد و ...
این کار با دستور set انجام میشود که نام متغیری را که باید ساخته شود میگیرد. مقدار تنظیم را میتوان به دو شیوه فراهم کرد:
یک ویژگی
t-valueحاوی یک عبارت، که نتیجهٔ ارزیابی آن تنظیم خواهد شد:<t t-set="foo" t-value="2 + 1"/> <t t-out="foo"/>
3را چاپ خواهد کرداگر ویژگی
t-valueوجود نداشته باشد، بدنهٔ گره رندر شده و بهعنوان مقدار متغیر تنظیم میشود:<t t-set="foo"> <li>ok</li> </t> <t t-out="foo"/>
فراخوانی زیرقالبها¶
قالبهای QWeb میتوانند برای رندر سطح بالا استفاده شوند، اما همچنین میتوانند از درون قالبی دیگر (برای جلوگیری از تکرار یا نامگذاری بخشهایی از قالبها) با استفاده از دستور t-call به کار روند:
<t t-call="other-template"/>
این، قالب نامبرده را با زمینهٔ اجرای والد فرامیخواند، اگر other_template به این صورت تعریف شده باشد:
<p><t t-value="var"/></p>
فراخوانی بالا بهصورت <p/> (بدون محتوا) رندر میشود، اما:
<t t-set="var" t-value="1"/>
<t t-call="other-template"/>
بهصورت <p>1</p> رندر خواهد شد.
با این حال، این مشکل را دارد که از بیرون t-call نیز قابل مشاهده است. بهعنوان جایگزین، محتوای تنظیمشده در بدنهٔ دستور call پیشاز فراخوانی زیرقالب ارزیابی میشود و میتواند زمینهای محلی را تغییر دهد:
<t t-call="other-template">
<t t-set="var" t-value="1"/>
</t>
<!-- "var" does not exist here -->
بدنهٔ دستور call میتواند بهدلخواه پیچیده باشد (نه فقط دستورهای set)، و شکل رندرشدهٔ آن در درون قالب فراخوانیشده بهعنوان متغیر جادویی 0 در دسترس خواهد بود:
<div>
This template was called with content:
<t t-out="0"/>
</div>
بدین شکل فراخوانی میشود:
<t t-call="other-template">
<em>content</em>
</t>
منجر میشود به:
<div>
This template was called with content:
<em>content</em>
</div>
خروجی پیشرفته¶
بهطور پیشفرض، out باید محتوایی را که نیاز به escape دارد بهصورت HTML escape کند تا سامانه را در برابر XSS محافظت کند
محتوایی که نیاز به escape ندارد، در عوض همانگونه که هست در سند تزریق میشود و ممکن است بخشی از markup واقعی سند شود.
تنها محتوای "امن" میانسکویی، خروجی t-call یا t-set استفادهشده با یک "body" (در مقابل t-value یا t-valuef) است.
پایتون¶
معمولاً نباید زیاد نگران آن باشید: APIهایی که این موضوع برایشان معنا دارد باید بهصورت خودکار محتوای "امن" تولید کنند و همهچیز باید بهطور شفاف کار کند.
برای مواردی که نیاز به شفافیت بیشتری باشد، APIهای زیر محتوای امن خروجی میدهند که هنگام تزریق به قالبها بهطور پیشفرض (دوباره) escape نخواهد شد:
فیلدهای HTML.html_escape()وmarkupsafe.escape()(نامهای مستعار هستند و خطر escape دوگانه ندارند).html_sanitize().markupsafe.Markup.هشدار
markupsafe.Markupیک API ناامن است؛ این یک ادعا است که میخواهید محتوا برای markup امن باشد اما لزوماً نمیتواند آن را بررسی کند؛ باید با احتیاط استفاده شود.to_text()محتوا را بهعنوان امن علامتگذاری نمیکند، اما این اطلاعات را از محتوای امن حذف نمیکند.
اعمال اجباری escape دوگانه¶
اگر محتوا بهعنوان امن علامتگذاری شده باشد اما به دلایلی نیاز به escape شدن داشته باشد (مثلاً چاپ markup یک فیلد HTML)، میتوان آن را به یک رشتهٔ معمولی تبدیل کرد تا پرچم امنی "حذف" شود؛ مثلاً str(content) در Python و String(content) در Javascript.
توجه
از آنجا که Markup نوعی بسیار غنیتر از Markup() است، برخی عملیات اطلاعات امن را از یک Markup() حذف میکنند اما از یک Markup خیر؛ مثلاً الحاق رشتهها ('' + content) در Python منجر به یک Markup میشود که عملوند دیگر بهدرستی escape شده است، در حالی که در Javascript یک String() تولید میکند که در آن عملوند دیگر پیش از الحاق escape نشده است.
دستورهای خروجی منسوخ¶
escنام مستعاری برای
out؛ در اصل ورودی خود را بهصورت HTML escape میکرد. هنوز رسماً منسوخ نشده است زیرا تنها تفاوت میانoutوescاین است که دومی کمی نامشخص/نادرست است.rawنسخهای از
outکه هرگز محتوای خود را escape نمیکند. محتوا همانگونه که هست منتشر میشود، چه امن باشد چه نباشد.منسوخ شده از نسخه 15.0: بهجای آن از
outبا یک مقدارmarkupsafe.Markupاستفاده کنید.t-rawمنسوخ شد زیرا با تکامل کدی که محتوا را تولید میکند، رهگیری اینکه برای markup استفاده خواهد شد میتواند دشوار باشد و به بازبینیهای پیچیدهتر و خطاهای خطرناکتر منجر شود.
پایتون¶
دستورهای انحصاری¶
بستههای دارایی¶
قالببندی فیلدهای "رکوردهای هوشمند"¶
دستور t-field تنها هنگام دسترسی به فیلد (a.b) روی یک رکورد "هوشمند" (نتیجهٔ متد browse) قابل استفاده است. این دستور میتواند بهصورت خودکار بر اساس نوع فیلد قالببندی کند و در ویرایش متن غنی وبسایت یکپارچه است.
از t-options میتوان برای سفارشیسازی فیلدها استفاده کرد؛ رایجترین گزینه widget است و سایر گزینهها وابسته به فیلد یا ویجت هستند.
اشکالزدایی¶
t-debugبا مقدار خالی، تابع داخلی
breakpoint()را فرامیخواند که معمولاً یک اشکالزدا را اجرا میکند (بهطور پیشفرضpdb).این رفتار را میتوان از طریق
PYTHONBREAKPOINTیاsys.breakpointhook()پیکربندی کرد.
کمکرسانها¶
مبتنی بر درخواست¶
بیشتر کاربردهای سمت Python از QWeb در کنترلرها (و در طول درخواستهای HTTP) است؛ در این حالت قالبهای ذخیرهشده در پایگاهداده (بهعنوان نماها) را میتوان بهسادگی با فراخوانی odoo.http.HttpRequest.render() رندر کرد:
response = http.request.render('my-template', {
'context_value': 42
})
این بهطور خودکار یک شیء Response میسازد که میتوان آن را از کنترلر بازگرداند (یا برای نیاز بیشتر سفارشیسازی کرد).
مبتنی بر نما¶
در سطحی عمیقتر از کمکرسان قبلی، متد _render روی ir.qweb (از پایگاهداده استفاده میکند) و متد عمومی ماژول render (از پایگاهداده استفاده نمیکند) قرار دارند:
- _render(id[, values])¶
یک نما/قالب QWeb را با شناسهٔ پایگاهداده یا external id رندر میکند. قالبها بهطور خودکار از رکوردهای
ir.qwebبارگذاری میشوند.متد
_prepare_environmentتعدادی مقدار پیشفرض را در زمینهٔ رندر تنظیم میکند. افزونههایhttp_routingوwebsiteنیز مقادیر پیشفرض مورد نیاز خود را دارند. میتوانید از گزینهٔminimal_qcontext=Falseبرای پرهیز از این مقدار پیشفرض، مانند متد عمومیrender، استفاده کنید:requestشیء
Requestجاری، در صورت وجودdebugاینکه آیا درخواست جاری (در صورت وجود) در حالت
debugاستquote_plusتابع کمکی برای رمزگذاری URL
jsonماژول متناظر کتابخانهٔ استاندارد
timeماژول متناظر کتابخانهٔ استاندارد
datetimeماژول متناظر کتابخانهٔ استاندارد
- relativedelta
نگاه کنید به ماژول
keep_queryتابع کمکرسان
keep_query
- پارامترها
values -- مقادیر زمینه برای ارسال به QWeb جهت رندر
engine (str) -- نام مدل Odoo مورد استفاده برای رندر؛ میتوان از آن برای گسترش یا سفارشیسازی محلی QWeb (با ایجاد یک qweb "جدید" بر اساس
ir.qwebبا تغییرات) استفاده کرد
- render(template_name, values, load, **options)¶
load(ref)()شیء etree و ref را بازمیگرداند
جاوااسکریپت¶
دستورهای انحصاری¶
تعریف قالبها¶
دستور t-name تنها میتواند در سطح بالای یک فایل قالب (بهعنوان فرزند مستقیم ریشهٔ سند) قرار گیرد:
<templates>
<t t-name="template-name">
<!-- template code -->
</t>
</templates>
پارامتر دیگری نمیگیرد، اما میتواند با یک عنصر <t> یا هر عنصر دیگری استفاده شود. با یک عنصر <t>، آن <t> باید تنها یک فرزند داشته باشد.
نام قالب یک رشتهٔ دلخواه است، اگرچه وقتی چندین قالب به هم مرتبط باشند (مثلاً زیرقالبهای فراخواندهشده) معمول است از نامهای جداشده با نقطه برای نشان دادن روابط سلسلهمراتبی استفاده شود.
وراثت قالب¶
- وراثت قالب برای یکی از این دو منظور استفاده میشود:
تغییر قالبهای موجود در محل، مثلاً برای افزودن اطلاعات به قالبها
- ساختهشده توسط ماژولهای دیگر.
ایجاد یک قالب جدید از یک قالب والد مشخص
- وراثت قالب با استفاده از دو دستور انجام میشود:
t-inheritکه نام قالبی است که از آن ارثبری میشود،t-inherit-modeکه رفتار وراثت را تعیین میکند: میتوان آن را رویprimaryتنظیم کرد تا یک قالب فرزند جدید از قالب والد ساخته شود، یا رویextensionتا قالب والد در محل تغییر یابد.
یک دستور اختیاری t-name نیز میتوان مشخص کرد. اگر در حالت primary استفاده شود نام قالب تازه ساختهشده خواهد بود، در غیر این صورت بهعنوان نظری روی قالب دگرگونشده افزوده میشود تا به ردیابی وراثتها کمک کند.
برای خود وراثت، تغییرات با استفاده از دستورهای xpath انجام میشوند. برای مجموعهٔ کامل دستورالعملهای موجود به مستندات XPATH مراجعه کنید.
وراثت اصلی (قالب فرزند):
<t t-name="child.template" t-inherit="base.template" t-inherit-mode="primary">
<xpath expr="//ul" position="inside">
<li>new element</li>
</xpath>
</t>
وراثت توسعهای (دگرگونی در محل):
<t t-inherit="base.template" t-inherit-mode="extension">
<xpath expr="//tr[1]" position="after">
<tr><td>new cell</td></tr>
</xpath>
</t>
سازوکار وراثت قدیمی (منسوخ)¶
وراثت قالب با دستور t-extend انجام میشود که نام قالب مورد تغییر را بهعنوان پارامتر میگیرد.
دستور t-extend در ترکیب با t-name بهعنوان وراثت اصلی و وقتی بهتنهایی استفاده شود بهعنوان وراثت توسعهای عمل میکند.
در هر دو حالت، سپس تغییر با هر تعداد زیردستور t-jquery انجام میشود:
<t t-extend="base.template">
<t t-jquery="ul" t-operation="append">
<li>new element</li>
</t>
</t>
دستورهای t-jquery یک CSS selector میگیرند. این انتخابگر روی قالب گسترشیافته برای انتخاب گرههای زمینهای بهکار میرود که t-operation مشخصشده روی آنها اعمال میشود:
appendبدنهٔ گره به انتهای گرهٔ زمینهای الحاق میشود (پس از آخرین فرزند گرهٔ زمینهای)
prependبدنهٔ گره به ابتدای گرهٔ زمینهای الحاق میشود (پیش از نخستین فرزند گرهٔ زمینهای درج میشود)
beforeبدنهٔ گره درست پیش از گرهٔ زمینهای درج میشود
afterبدنهٔ گره درست پس از گرهٔ زمینهای درج میشود
innerبدنهٔ گره جایگزین فرزندان گرهٔ زمینهای میشود
replaceبدنهٔ گره برای جایگزینی خود گرهٔ زمینهای استفاده میشود
attributesبدنهٔ گره باید شامل هر تعدادی از عناصر
attributeباشد، هر کدام با یک ویژگیnameو مقداری محتوای متنی؛ ویژگی نامبردهشده روی گرهٔ زمینهای به مقدار مشخصشده تنظیم میشود (در صورت وجود قبلی جایگزین میشود یا در غیر این صورت افزوده میشود)- بدون عملیات
اگر
t-operationمشخص نشود، بدنهٔ قالب بهعنوان کد javascript تفسیر و با گرهٔ زمینهای بهعنوانthisاجرا میشودهشدار
با وجود قدرت بسیار بیشتر نسبت به سایر عملیات، این حالت اشکالزدایی و نگهداری آن نیز بسیار دشوارتر است؛ پرهیز از آن توصیه میشود
اشکالزدایی¶
پیادهسازی javascript از QWeb چند قلاب اشکالزدایی فراهم میکند:
t-logیک پارامتر عبارت میگیرد، عبارت را در طول رندر ارزیابی میکند و نتیجه را با
console.logلاگ میکند:<t t-set="foo" t-value="42"/> <t t-log="foo"/>
42را به کنسول چاپ خواهد کردt-debugیک نقطهشکست اشکالزدا را در طول رندر قالب فعال میکند:
<t t-if="a_test"> <t t-debug=""/> </t>
اگر اشکالزدایی فعال باشد اجرا متوقف میشود (شرط دقیق بسته به مرورگر و ابزارهای توسعهٔ آن متفاوت است)
t-jsبدنهٔ گره کد javascript است که در طول رندر قالب اجرا میشود. یک پارامتر
contextمیگیرد که نامی است که زمینهٔ رندر در بدنهٔt-jsتحت آن نام در دسترس خواهد بود:<t t-set="foo" t-value="42"/> <t t-js="ctx"> console.log("Foo is", ctx.foo); </t>
کمکرسانها¶
- core.qweb¶
(core همان ماژول
web.coreاست) یک نمونه ازQWeb2.Engine()با تمام فایلهای قالب تعریفشده توسط ماژولها بارگذاریشده، و ارجاعهایی به اشیاء استاندارد کمکرسان_(underscore)،_t(تابع ترجمه) و JSON.از
core.qweb.renderمیتوان برای رندر آسان قالبهای پایهای ماژولها استفاده کرد
API¶
- class QWeb2.Engine()¶
"رندرر" QWeb بیشتر منطق QWeb را مدیریت میکند (بارگذاری، تجزیه، کامپایل و رندر قالبها).
Odoo Web در ماژول core یک نمونه برای کاربر میسازد و آن را به
core.qwebصادر میکند. همچنین تمام فایلهای قالب ماژولهای مختلف را در آن نمونهٔ QWeb بارگذاری میکند.یک
QWeb2.Engine()بهعنوان یک "فضای نام قالب" نیز عمل میکند.- QWeb2.Engine.QWeb2.Engine.render(template[, context])¶
یک قالب پیشتر بارگذاریشده را به یک رشته رندر میکند، با استفاده از
context(در صورت ارائه) برای یافتن متغیرهای دسترسییافته در طول رندر قالب (مثلاً رشتههای قابل نمایش).- نشانوندها
template (
String()) -- نام قالب موردنظر برای رندرcontext (
Object()) -- فضای نام پایه برای استفاده در رندر قالب
- بازگشت ها
رشته
موتور متد دیگری ارائه میدهد که در برخی موارد ممکن است مفید باشد (مثلاً اگر به فضای نام قالب جداگانه نیاز دارید؛ در Odoo Web، نماهای Kanban نمونهٔ
QWeb2.Engine()مخصوص به خود را دارند تا قالبهایشان با قالبهای عمومی "ماژول" تداخل پیدا نکند):- QWeb2.Engine.QWeb2.Engine.add_template(templates)¶
یک فایل قالب (مجموعهای از قالبها) را در نمونهٔ QWeb بارگذاری میکند. قالبها را میتوان به این صورتها مشخص کرد:
- یک رشتهٔ XML
QWeb تلاش میکند آن را به یک سند XML تجزیه کند و سپس بارگذاری نماید.
- یک URL
QWeb تلاش میکند محتوای URL را دانلود کند، سپس رشتهٔ XML حاصل را بارگذاری نماید.
- یک
DocumentیاNode QWeb نخستین سطح سند (گرههای فرزند ریشهٔ ارائهشده) را پیمایش میکند و هر قالب نامدار یا بازنویسی قالب را بارگذاری مینماید.
یک
QWeb2.Engine()همچنین ویژگیهای مختلفی برای سفارشیسازی رفتار ارائه میدهد:- QWeb2.Engine.QWeb2.Engine.prefix¶
پیشوند مورد استفاده برای شناسایی دستورها در طول تجزیه. یک رشته. بهطور پیشفرض،
t.
- QWeb2.Engine.QWeb2.Engine.debug¶
پرچم بولی که موتور را در "حالت اشکالزدایی" قرار میدهد. بهطور معمول، QWeb هر خطایی که در اجرای قالب رخ دهد را رهگیری میکند. در حالت اشکالزدایی، اجازه میدهد همهٔ استثناها بدون رهگیری عبور کنند.
- QWeb2.Engine.QWeb2.Engine.jQuery¶
نمونهٔ jQuery مورد استفاده در طول پردازش وراثت قالب. بهطور پیشفرض
window.jQuery.
- QWeb2.Engine.QWeb2.Engine.preprocess_node¶
یک
Function. در صورت وجود، پیش از کامپایل هر گرهٔ DOM به کد قالب فراخوانده میشود. در Odoo Web، این برای ترجمهٔ خودکار محتوای متنی و برخی ویژگیها در قالبها استفاده میشود. بهطور پیشفرضnull.