ID |
English原文 |
中文翻译 |
最近翻译记录 |
状态 |
操作 |
0#翻译 |
Chapter 10: Extending the Template Engine
-----------------------------------------
|
第十章: 深入模板引擎
-------------------- |
1425天前 |
|
翻译 |
1#翻译 |
Although most of your interactions with Djangos template language will be in
the role of template author, you may want to customize and extend the template
engine either to make it do something it doesnt already do, or to make your job
easier in some other way.
|
WJmyEN <a href="http://shdawlkicouq.com/">shdawlkicouq</a>, [url=http://xhmwoyqzgfmc.com/]xhmwoyqzgfmc[/url], [link=http://ulwsjkuwztds.com/]ulwsjkuwztds[/link], http://zozblfuuryro.com/ |
57天前 |
|
翻译 |
2#翻译 |
This chapter delves deep into the guts of Djangos template system. It covers
what you need to know if you plan to extend the system or if youre just curious
about how it works.
|
本章深入钻研Django的模板系统。如果你想扩展模板系统或者只是对它的工作原理感觉到好奇,本章涉及了你需要了解的东西. |
96天前 |
|
翻译 |
3#翻译 |
If youre looking to use the Django template system as part of another
application (i.e., without the rest of the framework), make sure to read the
Configuring the Template System in Standalone Mode section later in the
chapter.
|
如果你想把Django的模版系统作为另外一个应用程序的一部分(比如,仅使用django的模板系统而不使用Django框架的其他部分),那你一定要读一下“配置独立模式下的模版系统”这一节。 |
1247天前 |
|
翻译 |
4#翻译 |
Template Language Review
````````````````````````
|
MaxVAp <a href="http://xsivwbewqmrn.com/">xsivwbewqmrn</a>, [url=http://gncxzntjqedq.com/]gncxzntjqedq[/url], [link=http://fxbofzrzfowj.com/]fxbofzrzfowj[/link], http://mxccahhxsvoy.com/ |
64天前 |
|
翻译 |
5#翻译 |
First, lets quickly review a number of terms introduced in Chapter 4:
|
首先,让我们快速回顾一下第四章介绍的若干专业术语 |
1390天前 |
|
翻译 |
6#翻译 |
A *template* is a text document, or a normal Python string, that is marked
up using the Django template language. A template can contain block tags
and variables.
|
*模板* 是一个纯文本文件,或是一个用Django模板语言标记过的普通的Python字符串,一个模板可以包含区块标签和变量。 |
1247天前 |
|
翻译 |
7#翻译 |
A *block tag* is a symbol within a template that does something. This
definition is deliberately vague. For example, a block tag can produce
content, serve as a control structure (an ``if`` statement or ``for``
loop), grab content from a database, or enable access to other template
tags.
|
*区块标签* 是在一个模板里面起作用的的标记,这个定义故意说的很含糊,比如,一个
区块标签可以生成内容,可以作为一个控制结构( ``if`` 语句或 ``for`` 循环),
可以获取数据库内容,或者访问其他的模板标签。 |
1247天前 |
|
翻译 |
8#翻译 |
Block tags are surrounded by ``{%`` and ``%}`` :
|
区块标签被 ``{%`` 和 ``%}`` 包含: |
1071天前 |
|
翻译 |
11#翻译 |
A *variable* is a symbol within a template that outputs a value.
|
*变量* 是一个在模板里用来输出值的标记。 |
1247天前 |
|
翻译 |
12#翻译 |
Variable tags are surrounded by ``{{`` and ``}}`` :
|
636Md6 <a href="http://htvhlhufywbg.com/">htvhlhufywbg</a>, [url=http://xborgohwkwvg.com/]xborgohwkwvg[/url], [link=http://wdnbqpxfpopl.com/]wdnbqpxfpopl[/link], http://lmksosgzadaw.com/ |
56天前 |
|
翻译 |
15#翻译 |
A *context* is a name -> value mapping (similar to a Python dictionary)
that is passed to a template.
|
*context* 是一个传递给模板的名称到值的映射(类似Python字典)。 |
1247天前 |
|
翻译 |
16#翻译 |
A template *renders* a context by replacing the variable holes with values
from the context and executing all block tags.
|
KeBCRa <a href="http://samdayfjlhom.com/">samdayfjlhom</a>, [url=http://tqpfosapplax.com/]tqpfosapplax[/url], [link=http://ttkbcaqikqzp.com/]ttkbcaqikqzp[/link], http://hdccvanbqbjx.com/ |
64天前 |
|
翻译 |
17#翻译 |
For more details about the basics of these terms, refer back to Chapter 4.
|
关于这些基本概念更详细的内容,请参考第四章。 |
1247天前 |
|
翻译 |
18#翻译 |
The rest of this chapter discusses ways of extending the template engine.
First, though, lets take a quick look at a few internals left out of Chapter 4
for simplicity.
|
本章的其余部分讨论了扩展模板引擎的方法。首先,我们快速的看一下第四章遗留的内容。 |
1247天前 |
|
翻译 |
19#翻译 |
RequestContext and Context Processors
`````````````````````````````````````
|
RequestContext和Context处理器
````````````````````````````````````` |
1193天前 |
|
翻译 |
20#翻译 |
When rendering a template, you need a context. Usually this is an instance of
``django.template.Context`` , but Django also comes with a special subclass,
``django.template.RequestContext`` , that acts slightly differently.
``RequestContext`` adds a bunch of variables to your template context by
default things like the ``HttpRequest`` object or information about the
currently logged-in user.
|
你需要一段context来解析模板。一般情况下,这是一个 ``django.template.Context`` 的实例,不过在Django中还可以用一个特殊的子类, ``django.template.RequestContext`` ,这个运用起来稍微有些不同。
``RequestContext`` 默认地在模板context中加入了一些变量,如 ``HttpRequest`` 对象或当前登录用户的相关信息。
|
1247天前 |
|
翻译 |
21#翻译 |
Use ``RequestContext`` when you dont want to have to specify the same set of
variables in a series of templates. For example, consider these four views:
|
当你不想在一系例模板中都明确指定一些相同的变量时,你应该使用 ``RequestContext`` 。例如,看下面的四个视图: |
1247天前 |
|
翻译 |
24#翻译 |
(Note that were deliberately *not* using the ``render_to_response()`` shortcut
in these examples were manually loading the templates, constructing the context
objects and rendering the templates. Were spelling out all of the steps for the
purpose of clarity.)
|
(注意,在这些例子中,我们故意 *不* 使用 ``render_to_response()`` 这个快捷方法,而选择手动载入模板,手动构造context对象然后渲染模板。是为了能够清晰的说明所有步骤。)
|
1247天前 |
|
翻译 |
25#翻译 |
Each view passes the same three variables ``app`` , ``user`` and ``ip_address``
to its template. Wouldnt it be nice if we could remove that redundancy?
|
每个视图都给模板传入了三个相同的变量: ``app`` 、 ``user`` 和 ``ip_address`` 。如果我们能把这些冗余去掉会不会看起来更好? |
1247天前 |
|
翻译 |
26#翻译 |
``RequestContext`` and **context processors** were created to solve this
problem. Context processors let you specify a number of variables that get set
in each context automatically without you having to specify the variables in
each ``render_to_response()`` call. The catch is that you have to use
``RequestContext`` instead of ``Context`` when you render a template.
|
创建 ``RequestContext`` 和 **context处理器** 就是为了解决这个问题。Context处理器允许你设置一些变量,它们会在每个context中自动被设置好,而不必每次调用 ``render_to_response()`` 时都指定。要点就是,当你渲染模板时,你要用 ``RequestContext`` 而不是 ``Context`` 。 |
1247天前 |
|
翻译 |
27#翻译 |
The most low-level way of using context processors is to create some processors
and pass them to ``RequestContext`` . Heres how the above example could be
written with context processors:
|
最直接的做法是用context处理器来创建一些处理器并传递给 ``RequestContext`` 。上面的例子可以用context processors改写如下: |
1247天前 |
|
翻译 |
30#翻译 |
Lets step through this code:
|
我们来通读一下代码: |
1417天前 |
|
翻译 |
31#翻译 |
* First, we define a function ``custom_proc`` . This is a context processor
it takes an ``HttpRequest`` object and returns a dictionary of variables to
use in the template context. Thats all it does.
|
* 首先,我们定义一个函数 ``custom_proc`` 。这是一个context处理器,它接收一个 ``HttpRequest`` 对象,然后返回一个字典,这个字典中包含了可以在模板context中使用的变量。它就做了这么多。 |
1247天前 |
|
翻译 |
32#翻译 |
* Weve changed the four view functions to use ``RequestContext`` instead of
``Context`` . There are two differences in how the context is constructed.
One, ``RequestContext`` requires the first argument to be an
``HttpRequest`` object the one that was passed into the view function in
the first place (``request`` ). Two, ``RequestContext`` takes an optional
``processors`` argument, which is a list or tuple of context processor
functions to use. Here, we pass in ``custom_proc`` , the custom processor
we defined above.
|
* 我们在这四个视图函数中用 ``RequestContext`` 代替了 ``Context`` 。在context对象的构建上有两个不同点。一, ``RequestContext`` 的第一个参数需要传递一个 ``HttpRequest`` 对象,就是传递给视图函数的第一个参数( ``request`` )。二, ``RequestContext`` 有一个可选的参数 ``processors`` ,这是一个包含context处理器函数的list或者tuple。在这里,我们传递了我们之前定义的函数 ``curstom_proc`` 。 |
1247天前 |
|
翻译 |
33#翻译 |
* Each view no longer has to include ``app`` , ``user`` or ``ip_address`` in
its context construction, because those are provided by ``custom_proc`` .
|
* 每个视图的context结构里不再包含 ``app`` 、 ``user`` 、 ``ip_address`` 等变量,因为这些由 ``custom_proc`` 函数提供了。 |
1247天前 |
|
翻译 |
34#翻译 |
* Each view *still* has the flexibility to introduce any custom template
variables it might need. In this example, the ``message`` template variable
is set differently in each view.
|
O5akXl <a href="http://xrdylvofgyks.com/">xrdylvofgyks</a>, [url=http://jpknyzrymcvm.com/]jpknyzrymcvm[/url], [link=http://kanomsrvtkmd.com/]kanomsrvtkmd[/link], http://avajxtraqqjg.com/ |
56天前 |
|
翻译 |
35#翻译 |
In Chapter 4, we introduced the ``render_to_response()`` shortcut, which saves
you from having to call ``loader.get_template()`` , then create a ``Context`` ,
then call the ``render()`` method on the template. In order to demonstrate the
lower-level workings of context processors, the above examples didnt use
``render_to_response()`` , . But its possible and preferable to use context
processors with ``render_to_response()`` . Do this with the
``context_instance`` argument, like so:
|
在第四章,我们介绍了 ``render_to_response()`` 这个快捷方式,它可以省掉调用 ``loader.get_template()`` ,然后创建一个 ``Context`` 对象,最后再调用模板对象的 ``render()`` 方法。为了讲解context处理器底层是如何工作的,在上面的例子中我们没有使用 ``render_to_response()`` 。但是建议选择 ``render_to_response()`` 作为context的处理器。像这样,使用 ``context_instance`` 参数: |
1398天前 |
|
翻译 |
38#翻译 |
Here, weve trimmed down each views template rendering code to a single
(wrapped) line.
|
在这,我们将每个视图的模板渲染代码写成了一个单行。 |
1426天前 |
|
翻译 |
39#翻译 |
This is an improvement, but, evaluating the conciseness of this code, we have
to admit were now almost overdosing on the *other* end of the spectrum. Weve
removed redundancy in data (our template variables) at the cost of adding
redundancy in code (in the ``processors`` call). Using context processors
doesnt save you much typing if you have to type ``processors`` all the time.
|
虽然这是一种改进,但是,请考虑一下这段代码的简洁性,我们现在不得不承认的是在 *另外* 一方面有些过分了。我们以代码冗余(在 ``processors`` 调用中)的代价消除了数据上的冗余(我们的模板变量)。由于你不得不一直键入 ``processors`` ,所以使用context处理器并没有减少太多的打字次数。 |
1247天前 |
|
翻译 |
40#翻译 |
For that reason, Django provides support for *global* context processors. The
``TEMPLATE_CONTEXT_PROCESSORS`` setting designates which context processors
should *always* be applied to ``RequestContext`` . This removes the need to
specify ``processors`` each time you use ``RequestContext`` .
|
Django因此提供对 *全局* context处理器的支持。 ``TEMPLATE_CONTEXT_PROCESSORS`` 指定了 *总是* 使用哪些 ``context processors`` 。这样就省去了每次使用 ``RequestContext`` 都指定 ``processors`` 的麻烦^_^。 |
1247天前 |
|
翻译 |
41#翻译 |
By default, ``TEMPLATE_CONTEXT_PROCESSORS`` is set to the following:
|
ilR94N <a href="http://bxcyktdovtcx.com/">bxcyktdovtcx</a>, [url=http://svkmchcyqtpi.com/]svkmchcyqtpi[/url], [link=http://orlgauoznlpg.com/]orlgauoznlpg[/link], http://hcmltazhxlgv.com/ |
56天前 |
|
翻译 |
44#翻译 |
This setting is a tuple of callables that use the same interface as our
``custom_proc`` function above functions that take a request object as their
argument and return a dictionary of items to be merged into the context. Note
that the values in ``TEMPLATE_CONTEXT_PROCESSORS`` are specified as *strings* ,
which means the processors are required to be somewhere on your Python path (so
you can refer to them from the setting).
|
这个设置是一个可调用函数的Tuple,其中的每个函数使用了和上文中我们的 ``custom_proc`` 相同的接口:接收一个request对象作为参数,返回一个包含了将被合并到context中的项的字典。请注意 ``TEMPLATE_CONTEXT_PROCESSORS`` 中的值是以 *strings* 的形式给出的,这意味着这些处理器必须在你的python路径中的某处(这样你才能在设置中引用它们) |
1398天前 |
|
翻译 |
45#翻译 |
Each processor is applied in order. That is, if one processor adds a variable
to the context and a second processor adds a variable with the same name, the
second will override the first.
|
RkbRhS <a href="http://ssvglzgqktrs.com/">ssvglzgqktrs</a>, [url=http://tzwexwjpftqx.com/]tzwexwjpftqx[/url], [link=http://siituwbkjtet.com/]siituwbkjtet[/link], http://nyplxetpyqkq.com/ |
64天前 |
|
翻译 |
46#翻译 |
Django provides a number of simple context processors, including the ones that
are enabled by default:
|
Django提供了几个简单的context处理器,有些在默认情况下被启用的。 |
1247天前 |
|
翻译 |
47#翻译 |
django.core.context_processors.auth
'''''''''''''''''''''''''''''''''''
|
django.core.context_processors.auth
''''''''''''''''''''''''''''''''''' |
1409天前 |
|
翻译 |
48#翻译 |
If ``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
``RequestContext`` will contain these variables:
|
cZgBaF <a href="http://wqijjqhtuafe.com/">wqijjqhtuafe</a>, [url=http://ymyewzllgpwg.com/]ymyewzllgpwg[/url], [link=http://ynrosouewqcv.com/]ynrosouewqcv[/link], http://taptrifhfbme.com/ |
56天前 |
|
翻译 |
49#翻译 |
* ``user`` : A ``django.contrib.auth.models.User`` instance representing the
current logged-in user (or an ``AnonymousUser`` instance, if the client
isnt logged in).
|
* ``user`` :一个 ``django.contrib.auth.models.User`` 实例,描述了当前登录用户(或者一个 ``AnonymousUser`` 实例,如果客户端没有登录)。
|
1247天前 |
|
翻译 |
50#翻译 |
* ``messages`` : A list of messages (as strings) for the current logged-in
user. Behind the scenes, this variable calls
``request.user.get_and_delete_messages()`` for every request. That method
collects the users messages and deletes them from the database.
|
* ``messages`` :一个当前登录用户的消息列表(字符串)。在后台,对每一个请求这个变量都调用 ``request.user.get_and_delete_messages()`` 方法。这个方法收集用户的消息然后把它们从数据库中删除。 |
1247天前 |
|
翻译 |
51#翻译 |
* ``perms`` : An instance of ``django.core.context_processors.PermWrapper`` ,
which represents the permissions the current logged-in user has.
|
* ``perms`` : ``django.core.context_processors.PermWrapper`` 的一个实例,包含了当前登录用户有哪些权限。 |
1247天前 |
|
翻译 |
52#翻译 |
See Chapter 12 for more information on users, permissions, and messages.
|
关于users、permissions和messages的更多内容请参考第12章。 |
1247天前 |
|
翻译 |
53#翻译 |
django.core.context_processors.debug
''''''''''''''''''''''''''''''''''''
|
django.core.context_processors.debug
'''''''''''''''''''''''''''''''''''' |
1313天前 |
|
翻译 |
54#翻译 |
This processor pushes debugging information down to the template layer. If
``TEMPLATE_CONTEXT_PROCESSORS`` contains this processor, every
``RequestContext`` will contain these variables:
|
ae2cpK <a href="http://zekedeavaywg.com/">zekedeavaywg</a>, [url=http://kqzsnzwpeoko.com/]kqzsnzwpeoko[/url], [link=http://ncoswfhxxpgm.com/]ncoswfhxxpgm[/link], http://vrswcfxjqbnl.com/ |
57天前 |
|
翻译 |
55#翻译 |
* ``debug`` : The value of your ``DEBUG`` setting (either ``True`` or
``False`` ). You can use this variable in templates to test whether youre
in debug mode.
|
* ``debug`` :你设置的 ``DEBUG`` 的值( ``True`` 或 ``False`` )。你可以在模板里面用这个变量测试是否处在debug模式下。 |
1247天前 |
|
翻译 |
56#翻译 |
* ``sql_queries`` : A list of ``{'sql': ..., 'time': ...}`` dictionaries
representing every SQL query that has happened so far during the request
and how long it took. The list is in the order in which the queries were
issued.
|
* ``sql_queries`` :包含类似于 ``{'sql': ..., 'time': ...}`` 的字典的一个列表,
记录了这个请求期间的每个SQL查询以及查询所耗费的时间。这个列表是按照请求顺序进行排列的。 |
1247天前 |
|
翻译 |
57#翻译 |
Because debugging information is sensitive, this context processor will only
add variables to the context if both of the following conditions are true:
|
由于调试信息比较敏感,所以这个context处理器只有当同时满足下面两个条件的时候才有效: |
1426天前 |
|
翻译 |
58#翻译 |
* The ``DEBUG`` setting is ``True`` .
|
VB156E <a href="http://xsstdaarnodo.com/">xsstdaarnodo</a>, [url=http://sjvwzwjuntje.com/]sjvwzwjuntje[/url], [link=http://rllxfurtgmdb.com/]rllxfurtgmdb[/link], http://liaaqrivlsgl.com/ |
56天前 |
|
翻译 |
59#翻译 |
* The request came from an IP address in the ``INTERNAL_IPS`` setting.
|
* 请求的ip应该包含在 ``INTERNAL_IPS`` 的设置里面。
|
1247天前 |
|
翻译 |
60#翻译 |
django.core.context_processors.i18n
'''''''''''''''''''''''''''''''''''
|
django.core.context_processors.i18n
''''''''''''''''''''''''''''''''''' |
1303天前 |
|
翻译 |
61#翻译 |
If this processor is enabled, every ``RequestContext`` will contain these
variables:
|
如果这个处理器启用,每个 ``RequestContext`` 将包含下面的变量: |
1418天前 |
|
翻译 |
62#翻译 |
* ``LANGUAGES`` : The value of the ``LANGUAGES`` setting.
|
* ``LANGUAGES`` : ``LANGUAGES`` 选项的值。
|
1247天前 |
|
翻译 |
63#翻译 |
* ``LANGUAGE_CODE`` : ``request.LANGUAGE_CODE`` if it exists; otherwise, the
value of the ``LANGUAGE_CODE`` setting.
|
* ``LANGUAGE_CODE`` :如果 ``request.LANGUAGE_CODE`` 存在,就等于它;否则,等同于 ``LANGUAGE_CODE`` 设置。
|
1247天前 |
|
翻译 |
64#翻译 |
Appendix E provides more information about these two settings.
|
附录E提供了有关这两个设置的更多的信息。 |
1472天前 |
|
翻译 |
65#翻译 |
django.core.context_processors.request
''''''''''''''''''''''''''''''''''''''
|
django.core.context_processors.request
'''''''''''''''''''''''''''''''''''''' |
1303天前 |
|
翻译 |
66#翻译 |
If this processor is enabled, every ``RequestContext`` will contain a variable
``request`` , which is the current ``HttpRequest`` object. Note that this
processor is not enabled by default; you have to activate it.
|
zEZko4 <a href="http://davktzvegpga.com/">davktzvegpga</a>, [url=http://dvvitkvkrqhj.com/]dvvitkvkrqhj[/url], [link=http://zmxecatgkrei.com/]zmxecatgkrei[/link], http://qxqjkagkmvbm.com/ |
57天前 |
|
翻译 |
67#翻译 |
Guidelines for Writing Your Own Context Processors
''''''''''''''''''''''''''''''''''''''''''''''''''
|
写Context处理器的一些建议
''''''''''''''''''''''''' |
1247天前 |
|
翻译 |
68#翻译 |
Here are a few tips for rolling your own:
|
编写处理器的一些建议: |
1247天前 |
|
翻译 |
69#翻译 |
* Make each context processor responsible for the smallest subset of
functionality possible. Its easy to use multiple processors, so you might
as well split functionality into logical pieces for future reuse.
|
* 使每个context处理器完成尽可能小的功能。
使用多个处理器是很容易的,所以你可以根据逻辑块来分解功能以便将来重用。 |
1247天前 |
|
翻译 |
70#翻译 |
* Keep in mind that any context processor in ``TEMPLATE_CONTEXT_PROCESSORS``
will be available in *every* template powered by that settings file, so try
to pick variable names that are unlikely to conflict with variable names
your templates might be using independently. As variable names are
case-sensitive, its not a bad idea to use all caps for variables a
processor provides.
|
* 要注意 ``TEMPLATE_CONTEXT_PROCESSORS`` 里的context processor
将会在 *每个* 模板中有效,所以要变量的命名不要和模板的变量冲突。
变量名是大小写敏感的,所以processor的变量全用大写是个不错的主意。 |
1418天前 |
|
翻译 |
71#翻译 |
* It doesnt matter where on the filesystem they live, as long as theyre on
your Python path so you can point to them from the
``TEMPLATE_CONTEXT_PROCESSORS`` setting. With that said, the convention is
to save them in a file called ``context_processors.py`` within your app or
project.
|
* 只要它们存放在你的Python的搜索路径中,它们放在哪个物理路径并不重要,这样你可以在 ``TEMPLATE_CONTEXT_PROCESSORS`` 设置里指向它们。 也就是说,你要把它们放在app或者project目录里名为 ``context_processors.py`` 的文件。
|
1269天前 |
|
翻译 |
72#翻译 |
Inside Template Loading
```````````````````````
|
模板加载的内幕
`````````````` |
1472天前 |
|
翻译 |
73#翻译 |
Generally, youll store templates in files on your filesystem, but you can use
custom *template loaders* to load templates from other sources.
|
一般说来,你会把模板以文件的方式存储在文件系统中,但是你也可以使用自定义的 *template loaders* 从其他来源加载模板。 |
1424天前 |
|
翻译 |
74#翻译 |
Django has two ways to load templates:
|
Django有两种方法加载模板 |
1472天前 |
|
翻译 |
75#翻译 |
* ``django.template.loader.get_template(template_name)`` : ``get_template``
returns the compiled template (a ``Template`` object) for the template with
the given name. If the template doesnt exist, a ``TemplateDoesNotExist``
exception will be raised.
|
* ``django.template.loader.get_template(template_name)`` : ``get_template`` 根据给定的模板名称返回一个已编译的模板(一个 ``Template`` 对象)。如果模板不存在,就触发 ``TemplateDoesNotExist`` 的异常。 |
1247天前 |
|
翻译 |
76#翻译 |
* ``django.template.loader.select_template(template_name_list)`` :
``select_template`` is just like ``get_template`` , except it takes a list
of template names. Of the list, it returns the first template that exists.
If none of the templates exist, a ``TemplateDoesNotExist`` exception will
be raised.
|
* ``django.template.loader.select_template(template_name_list)`` : ``select_template`` 很像 ``get_template`` ,不过它是以模板名称的列表作为参数的,并且它返回第一个存在的模板。如果模板都不存在,将会触发 ``TemplateDoesNotExist`` 异常。 |
1247天前 |
|
翻译 |
77#翻译 |
As covered in Chapter 4, each of these functions by default uses your
``TEMPLATE_DIRS`` setting to load templates. Internally, however, these
functions actually delegate to a template loader for the heavy lifting.
|
正如在第四章中所提到的,默认情况下这些函数使用 ``TEMPLATE_DIRS`` 的设置来载入模板。但是,在内部这些函数可以指定一个模板加载器来完成这些繁重的任务。 |
1378天前 |
|
翻译 |
78#翻译 |
Some of loaders are disabled by default, but you can activate them by editing
the ``TEMPLATE_LOADERS`` setting. ``TEMPLATE_LOADERS`` should be a tuple of
strings, where each string represents a template loader. These template loaders
ship with Django:
|
一些加载器默认被禁用,但是你可以通过编辑 ``TEMPLATE_LOADERS`` 设置来激活它们。 ``TEMPLATE_LOADERS`` 应当是一个字符串的元组,其中每个字符串都表示一个模板加载器。这些模板加载器随Django一起发布。 |
1247天前 |
|
翻译 |
79#翻译 |
``django.template.loaders.filesystem.load_template_source`` : This loader
loads templates from the filesystem, according to ``TEMPLATE_DIRS`` . It is
enabled by default.
|
``django.template.loaders.filesystem.load_template_source`` : 这个加载器根据 ``TEMPLATE_DIRS`` 的设置从文件系统加载模板。在默认情况下这个加载器被启用. |
1398天前 |
|
翻译 |
80#翻译 |
``django.template.loaders.app_directories.load_template_source`` : This
loader loads templates from Django applications on the filesystem. For each
application in ``INSTALLED_APPS`` , the loader looks for a ``templates``
subdirectory. If the directory exists, Django looks for templates there.
|
``django.template.loaders.app_directories.load_template_source`` : 这个加
载器从文件系统上的Django应用中加载模板。对 ``INSTALLED_APPS`` 中的每个应用,这个加
载器会查找一个 ``templates`` 子目录。如果这个目录存在,Django就在那里寻找模板。 |
1247天前 |
|
翻译 |
81#翻译 |
This means you can store templates with your individual applications,
making it easy to distribute Django applications with default templates.
For example, if ``INSTALLED_APPS`` contains ``('myproject.polls',
'myproject.music')`` , then ``get_template('foo.html')`` will look for
templates in this order:
|
这意味着你可以把模板和你的应用一起保存,从而使得Django应用更容易和默认模板一起发布。例如,如果 ``INSTALLED_APPS`` 包含 ``('myproject.polls','myproject.music')`` ,那么 ``get_template('foo.html')`` 会按这个顺序查找模板: |
1398天前 |
|
翻译 |
82#翻译 |
* ``/path/to/myproject/polls/templates/foo.html``
|
* ``/path/to/myproject/polls/templates/foo.html``
|
1303天前 |
|
翻译 |
83#翻译 |
* ``/path/to/myproject/music/templates/foo.html``
|
zS7gE0 <a href="http://xihwijxziqzw.com/">xihwijxziqzw</a>, [url=http://latxmxlseqcl.com/]latxmxlseqcl[/url], [link=http://fwlitcrfihxf.com/]fwlitcrfihxf[/link], http://yxtsdtenuwcv.com/ |
64天前 |
|
翻译 |
84#翻译 |
Note that the loader performs an optimization when it is first imported: it
caches a list of which ``INSTALLED_APPS`` packages have a ``templates``
subdirectory.
|
请注意加载器在首次被导入的时候会执行一个优化:它会缓存一个列表,这个列表包含了 ``INSTALLED_APPS`` 中带有 ``templates`` 子目录的包。 |
1398天前 |
|
翻译 |
85#翻译 |
This loader is enabled by default.
|
这个加载器默认启用。 |
1409天前 |
|
翻译 |
86#翻译 |
``django.template.loaders.eggs.load_template_source`` : This loader is just
like ``app_directories`` , except it loads templates from Python eggs
rather than from the filesystem. This loader is disabled by default; youll
need to enable it if youre using eggs to distribute your application.
|
``django.template.loaders.eggs.load_template_source`` : 这个加载器类似 ``app_directories`` ,只不过它从Python eggs而不是文件系统中加载模板。这个加载器默认被禁用;如果你使用eggs来发布你的应用,那么你就需要启用它。 |
1398天前 |
|
翻译 |
87#翻译 |
Django uses the template loaders in order according to the ``TEMPLATE_LOADERS``
setting. It uses each loader until a loader finds a match.
|
Django按照 ``TEMPLATE_LOADERS`` 设置中的顺序使用模板加载器。它逐个使用每个加载器直至找到一个匹配的模板。 |
1398天前 |
|
翻译 |
88#翻译 |
Extending the Template System
`````````````````````````````
|
扩展模板系统
````````````````````````````` |
1417天前 |
|
翻译 |
89#翻译 |
Now that you understand a bit more about the internals of the template system,
lets look at how to extend the system with custom code.
|
既然你已经对模板系统的内幕了解多了一些,让我们来看看如何使用自定义的代码来拓展这个系统吧。 |
1409天前 |
|
翻译 |
90#翻译 |
Most template customization comes in the form of custom template tags and/or
filters. Although the Django template language comes with many built-in tags
and filters, youll probably assemble your own libraries of tags and filters
that fit your own needs. Fortunately, its quite easy to define your own
functionality.
|
绝大部分的模板定制是以自定义标签/过滤器的方式来完成的。尽管Django模板语言自带了许多内建标签和过滤器,但是你可能还是需要组建你自己的标签和过滤器库来满足你的需要。幸运的是,定义你自己的功能非常容易。 |
1065天前 |
|
翻译 |
91#翻译 |
Creating a Template Library
'''''''''''''''''''''''''''
|
创建一个模板库
'''''''''''''''''' |
1472天前 |
|
翻译 |
92#翻译 |
Whether youre writing custom tags or filters, the first thing to do is to
create a **template library** a small bit of infrastructure Django can hook
into.
|
不管是写自定义标签还是过滤器,第一件要做的事是给 **template library** 创建使Django能够勾入的机制。 |
1398天前 |
|
翻译 |
93#翻译 |
Creating a template library is a two-step process:
|
创建一个模板库分两步走: |
1472天前 |
|
翻译 |
94#翻译 |
First, decide which Django application should house the template library.
If youve created an app via ``manage.py startapp`` , you can put it in
there, or you can create another app solely for the template library.
|
第一,决定哪个Django应用应当拥有这个模板库。如果你通过 ``manage.py startapp`` 创建了一个应用,你可以把它放在那里,或者你可以为模板库单独创建一个应用。 |
1398天前 |
|
翻译 |
95#翻译 |
Whichever route you take, make sure to add the app to your
``INSTALLED_APPS`` setting. Well explain this shortly.
|
无论你采用何种方式,请确保把你的应用添加到 ``INSTALLED_APPS`` 中。我们稍后会解释这一点。 |
1398天前 |
|
翻译 |
96#翻译 |
Second, create a ``templatetags`` directory in the appropriate Django
applications package. It should be on the same level as ``models.py`` ,
``views.py`` , and so forth. For example:
|
第二,在适当的Django应用包里创建一个 ``templatetags`` 目录。这个目录应当和 ``models.py`` 、 ``views.py`` 等处于同一层次。例如: |
1247天前 |
|
翻译 |
99#翻译 |
Create two empty files in the ``templatetags`` directory: an
``__init__.py`` file (to indicate to Python that this is a package
containing Python code) and a file that will contain your custom tag/filter
definitions. The name of the latter file is what youll use to load the tags
later. For example, if your custom tags/filters are in a file called
``poll_extras.py`` , youd write the following in a template:
|
在 ``templatetags`` 中创建两个空文件:一个 ``__init__.py`` (告诉Python这是
一个包含了Python代码的包)和一个用来存放你自定义的标签/过滤器定义的文件。第二个文件
的名字稍后将用来加载标签。例如,如果你的自定义标签/过滤器在一个叫作
``poll_extras.py`` 的文件中,你需要在模板中写入如下内容: |
1247天前 |
|
翻译 |
102#翻译 |
The ``{% load %}`` tag looks at your ``INSTALLED_APPS`` setting and only
allows the loading of template libraries within installed Django
applications. This is a security feature; it allows you to host Python code
for many template libraries on a single computer without enabling access to
all of them for every Django installation.
|
``{% load %}`` 标签检查 ``INSTALLED_APPS`` 中的设置,仅允许加载已安装的Django应用程序中的模板库。这是一个安全特性。它可以让你在一台电脑上部署很多的模板库的代码,而又不用把它们暴露给每一个Django安装。 |
1247天前 |
|
翻译 |
103#翻译 |
If you write a template library that isnt tied to any particular models/views,
its valid and quite normal to have a Django application package that contains
only a ``templatetags`` package. Theres no limit on how many modules you put in
the ``templatetags`` package. Just keep in mind that a ``{% load %}`` statement
will load tags/filters for the given Python module name, not the name of the
application.
|
如果你写了一个不和任何模型/视图关联的模板库,那么得到一个仅包含 ``templatetags`` 包的Django应用程序包是完全正常的。对于在 ``templatetags`` 包中放置多少个模块没有做任何的限制。需要了解的是: ``{% load %}`` 语句会为指定的Python模块名(而非应用程序名)加载标签或过滤器。
|
1247天前 |
|
翻译 |
104#翻译 |
Once youve created that Python module, youll just have to write a bit of Python
code, depending on whether youre writing filters or tags.
|
一旦创建了Python模块,你只需根据是要编写过滤器还是标签来相应的编写一些Python代码。 |
1247天前 |
|
翻译 |
105#翻译 |
To be a valid tag library, the module must contain a module-level variable
named ``register`` that is a ``template.Library`` instance. This
``template.Library`` instance is the data structure in which all the tags and
filters are registered. So, near the top of your module, insert the following:
|
要成为有效的标签库,模块必须包含一个模块级的变量: ``register`` ,这是一个 ``template.Library`` 的实例。这个 ``template.Library`` 实例是包含所有已注册的标签及过滤器的数据结构。因此,在模块的顶部位置插入下述代码: |
1247天前 |
|
翻译 |
108#翻译 |
Note
|
备注 |
1449天前 |
|
翻译 |
109#翻译 |
For a good number of examples, read the source code for Djangos default filters
and tags. Theyre in ``django/template/defaultfilters.py`` and
``django/template/defaulttags.py`` , respectively. Some applications in
``django.contrib`` also contain template libraries.
|
请阅读Django默认的过滤器和标签的源码,那里有大量的例子。他们分别为: ``django/template/defaultfilters.py`` 和 ``django/template/defaulttags.py`` 。某些应用程序在 ``django.contrib`` 中也包含模板库。 |
1247天前 |
|
翻译 |
110#翻译 |
Once youve created this ``register`` variable, youll use it to create template
filters and tags.
|
创建 ``register`` 变量后,你就可以使用它来创建模板的过滤器和标签了。 |
1247天前 |
|
翻译 |
111#翻译 |
Writing Custom Template Filters
'''''''''''''''''''''''''''''''
|
自定义模板过滤器
'''''''''''''''''''''''''''''''
|
1417天前 |
|
翻译 |
112#翻译 |
Custom filters are just Python functions that take one or two arguments:
|
自定义过滤器就是有一个或两个参数的Python函数: |
1417天前 |
|
翻译 |
113#翻译 |
* The value of the variable (input)
|
* (输入)变量的值 |
1417天前 |
|
翻译 |
114#翻译 |
* The value of the argument, which can have a default value or be left out
altogether
|
* 参数的值, 可以是默认值或者完全留空 |
1401天前 |
|
翻译 |
115#翻译 |
For example, in the filter ``{{ var|foo:"bar" }}`` , the filter ``foo`` would
be passed the contents of the variable ``var`` and the argument ``"bar"`` .
|
例如,在过滤器 ``{{ var|foo:"bar" }}`` 中 ,过滤器 ``foo`` 会被传入变量 ``var`` 和参数 ``bar`` 的内容。 |
1398天前 |
|
翻译 |
116#翻译 |
Filter functions should always return something. They shouldnt raise
exceptions, and they should fail silently. If theres an error, they should
return either the original input or an empty string, whichever makes more
sense.
|
过滤器函数应该总有返回值,而且不能触发异常,它们都应该静静的失败。如果有一个错误发生,它们要么返回原始的输入字符串,要么返回空的字符串,无论哪个都可以。 |
1401天前 |
|
翻译 |
117#翻译 |
Heres an example filter definition:
|
这里是一些定义过滤器的例子: |
1406天前 |
|
翻译 |
120#翻译 |
And heres an example of how that filter would be used:
|
这里是一些如何使用过滤器的例子: |
1406天前 |
|
翻译 |
123#翻译 |
Most filters dont take arguments. In this case, just leave the argument out of
your function:
|
大多数过滤器并不需要参数。下面的例子把参数从你的函数中拿掉了: |
1401天前 |
|
翻译 |
126#翻译 |
When youve written your filter definition, you need to register it with your
``Library`` instance, to make it available to Djangos template language:
|
当你在定义你的过滤器时,你需要用 ``Library`` 实例来注册它,这样就能通过Django的模板语言来使用了: |
1398天前 |
|
翻译 |
129#翻译 |
The ``Library.filter()`` method takes two arguments:
|
``Library.filter()`` 方法需要两个参数: |
1404天前 |
|
翻译 |
130#翻译 |
* The name of the filter (a string)
|
* 过滤器的名称(一个字串) |
1406天前 |
|
翻译 |
131#翻译 |
* The filter function itself
|
* 过滤器函数本身 |
1406天前 |
|
翻译 |
132#翻译 |
If youre using Python 2.4 or above, you can use ``register.filter()`` as a
decorator instead:
|
如果你使用的是Python 2.4或更新,你可以使用 ``register.filter()`` 作为一个装饰器: |
1398天前 |
|
翻译 |
135#翻译 |
If you leave off the ``name`` argument, as in the second example, Django will
use the functions name as the filter name.
|
像第二个例子中,如果你不使用 ``name`` 参数,那么Django将会使用函数名作为过滤器的名字。 |
1398天前 |
|
翻译 |
136#翻译 |
Here, then, is a complete template library example, supplying the ``cut``
filter:
|
下面是一个完整的模板库的例子,提供了一个 ``cut`` 过滤器: |
1398天前 |
|
翻译 |
139#翻译 |
Writing Custom Template Tags
''''''''''''''''''''''''''''
|
自定义模板标签
'''''''''''''' |
1247天前 |
|
翻译 |
140#翻译 |
Tags are more complex than filters, because tags can do nearly anything.
|
标签要比过滤器复杂些,标签几乎能做任何事情。 |
1247天前 |
|
翻译 |
141#翻译 |
Chapter 4 describes how the template system works in a two-step process:
compiling and rendering. To define a custom template tag, you need to tell
Django how to manage both steps when it gets to your tag.
|
第四章描述了模板系统的两步处理过程:编译和呈现。为了自定义一个这样的模板标签,你需要告诉Django当遇到你的标签时怎样进行这过程。 |
1405天前 |
|
翻译 |
142#翻译 |
When Django compiles a template, it splits the raw template text into *nodes* .
Each node is an instance of ``django.template.Node`` and has a ``render()``
method. Thus, a compiled template is simply a list of ``Node`` objects.
|
当Django编译一个模板时,它将原始模板分成一个个 *节点* 。每个节点都是 ``django.template.Node`` 的一个实例,并且具备 ``render()`` 方法。于是,一个已编译的模板就是 ``Node`` 对象的一个列表。 |
1398天前 |
|
翻译 |
143#翻译 |
When you call ``render()`` on a compiled template, the template calls
``render()`` on each ``Node`` in its node list, with the given context. The
results are all concatenated together to form the output of the template. Thus,
to define a custom template tag, you specify how the raw template tag is
converted into a ``Node`` (the compilation function) and what the nodes
``render()`` method does.
|
当你调用一个已编译模板的 ``render()`` 方法时,模板就会用给定的context来调用每个在它的节点列表上的节点的 ``render()`` 方法。所以,为了定义一个自定义的模板标签,你需要明确这个模板标签转换为一个 ``Node`` (已编译的函数)和这个node的 ``render()`` 方法。 |
1398天前 |
|
翻译 |
144#翻译 |
In the sections that follow, we cover all the steps in writing a custom tag.
|
在下面的章节中,我们将详细解说写一个自定义标签时的所有步骤。 |
1401天前 |
|
翻译 |
145#翻译 |
Writing the Compilation Function
................................
|
编写编译函数
................................ |
1401天前 |
|
翻译 |
146#翻译 |
For each template tag it encounters, the template parser calls a Python
function with the tag contents and the parser object itself. This function is
responsible for returning a ``Node`` instance based on the contents of the tag.
|
当遇到一个模板标签(template tag)时,模板解析器就会把标签包含的内容,以及模板解析器自己作为参数调用一个python函数。这个函数负责返回一个和当前模板标签内容相对应的节点(Node)的实例。 |
1396天前 |
|
翻译 |
147#翻译 |
For example, lets write a template tag, ``{% current_time %}`` , that displays
the current date/time, formatted according to a parameter given in the tag, in
``strftime`` syntax (see ``http://www.djangoproject.com/r/python/strftime/`` ).
Its a good idea to decide the tag syntax before anything else. In our case,
lets say the tag should be used like this:
|
例如,写一个显示当前日期的模板标签:{% current_time %},该标签会根据参数指定的 ``strftime`` 格式(参见: ``http://www.djangoproject.com/r/python/strftime/`` )显示当前时间。在继续做其它事情以前,先决定标签的语法是一个好主意。在我们的例子里,该标签将会像这样被使用: |
1247天前 |
|
翻译 |
150#翻译 |
Note
|
备注 |
1406天前 |
|
翻译 |
151#翻译 |
Yes, this template tag is redundantDjangos default ``{% now %}`` tag does the
same task with simpler syntax. This template tag is presented here just for
example purposes.
|
没错, 这个模板标签是多余的,Django默认的 ``{% now %}`` 用更简单的语法完成了同样的工作。这个模板标签在这里只是作为一个例子。
|
1247天前 |
|
翻译 |
152#翻译 |
The parser for this function should grab the parameter and create a ``Node``
object:
|
这个函数的分析器会获取参数并创建一个 ``Node`` 对象: |
1398天前 |
|
翻译 |
155#翻译 |
Theres actually a lot going here:
|
其实这儿包含了不少东西: |
1313天前 |
|
翻译 |
156#翻译 |
* ``parser`` is the template parser object. We dont need it in this example.
|
* ``parser`` 是模板分析器对象,在这个例子中我们没有使用它。
|
1247天前 |
|
翻译 |
157#翻译 |
* ``token.contents`` is a string of the raw contents of the tag. In our
example, its ``'current_time "%Y-%m-%d %I:%M %p"'`` .
|
* ``token.contents`` 是包含有标签原始内容的字符串。在我们的例子中,它是 ``'current_time "%Y-%m-%d %I:%M %p"'`` 。
|
1247天前 |
|
翻译 |
158#翻译 |
* The ``token.split_contents()`` method separates the arguments on spaces
while keeping quoted strings together. Avoid using
``token.contents.split()`` (which just uses Pythons standard
string-splitting semantics). Its not as robust, as it naively splits on
*all* spaces, including those within quoted strings.
|
* ``token.split_contents()`` 方法按空格拆分参数同时保证引号中的字符串在一起。应该避免使用 ``token.contents.split()`` (仅是使用Python的标准字符串拆分),它不够健壮,因为它只是简单的按照 *所有* 空格进行拆分,包括那些引号引起来的字符串中的空格。
|
1247天前 |
|
翻译 |
159#翻译 |
* This function is responsible for raising
``django.template.TemplateSyntaxError`` , with helpful messages, for any
syntax error.
|
* 这个函数负责抛出 ``django.template.TemplateSyntaxError`` ,同时提供所有语法错误的有用信息。
|
1247天前 |
|
翻译 |
160#翻译 |
* Dont hard-code the tags name in your error messages, because that couples
the tags name to your function. ``token.split_contents()[0]`` will *always*
be the name of your tageven when the tag has no arguments.
|
* 不要把标签名称硬编码在你的错误信息中,因为这样会把标签名称和你的函数耦合在一起。 ``token.split_contents()[0]`` *总会是* 是你的标签的名称,即使标签没有参数。
|
1247天前 |
|
翻译 |
161#翻译 |
* The function returns a ``CurrentTimeNode`` (which well create shortly)
containing everything the node needs to know about this tag. In this case,
it just passes the argument ``"%Y-%m-%d %I:%M %p"`` . The leading and
trailing quotes from the template tag are removed with
``format_string[1:-1]`` .
|
* 这个函数返回一个 ``CurrentTimeNode`` (稍后我们将创建它),它包含了节点需要知道的关于这个标签的全部信息。在这个例子中,它只是传递了参数 ``"%Y-%m-%d %I:%M %p"`` 。模板标签开头和结尾的引号使用 ``format_string[1:-1]`` 除去。 |
1247天前 |
|
翻译 |
162#翻译 |
* Template tag compilation functions *must* return a ``Node`` subclass; any
other return value is an error.
|
* 模板标签编译函数 *必须* 返回一个 ``Node`` 子类,返回其它值都是错的。 |
1247天前 |
|
翻译 |
163#翻译 |
Writing the Template Node
.........................
|
编写模板节点
......................... |
1269天前 |
|
翻译 |
164#翻译 |
The second step in writing custom tags is to define a ``Node`` subclass that
has a ``render()`` method. Continuing the preceding example, we need to define
``CurrentTimeNode`` :
|
编写自定义标签的第二步就是定义一个拥有 ``render()`` 方法的 ``Node`` 子类。继续前面的例子,我们需要定义 ``CurrentTimeNode`` : |
1247天前 |
|
翻译 |
167#翻译 |
These two functions (``__init__`` and ``render`` ) map directly to the two
steps in template processing (compilation and rendering). Thus, the
initialization function only needs to store the format string for later use,
and the ``render()`` function does the real work.
|
这两个函数( ``__init__`` 和 ``render`` )与模板处理中的两步(编译与渲染)直接对应。这样,初始化函数仅仅需要存储后面要用到的格式字符串,而 ``render()`` 函数才做真正的工作。 |
1247天前 |
|
翻译 |
168#翻译 |
Like template filters, these rendering functions should fail silently instead
of raising errors. The only time that template tags are allowed to raise errors
is at compilation time.
|
与模板过滤器一样,这些渲染函数应该捕获错误,而不是抛出错误。模板标签只能在编译的时候才能抛出错误。 |
1247天前 |
|
翻译 |
169#翻译 |
Registering the Tag
...................
|
注册标签
...................
|
1401天前 |
|
翻译 |
170#翻译 |
Finally, you need to register the tag with your modules ``Library`` instance.
Registering custom tags is very similar to registering custom filters (as
explained above). Just instantiate a ``template.Library`` instance and call its
``tag()`` method. For example:
|
最后,你需要用你的模块 ``Library`` 实例注册这个标签。注册自定义标签与注册自定义过滤器非常类似(如前文所述)。实例化一个 ``template.Library`` 实例然后调用它的 ``tag()`` 方法。例如: |
1247天前 |
|
翻译 |
173#翻译 |
The ``tag()`` method takes two arguments:
|
``tag()`` 方法需要两个参数: |
1260天前 |
|
翻译 |
174#翻译 |
The name of the template tag (string). If this is left out, the
|
模板标签的名字(字符串)。如果被遗漏的话,将会使用编译函数的名字。 |
1247天前 |
|
翻译 |
175#翻译 |
name of the compilation function will be used.
|
|
1247天前 |
|
翻译 |
176#翻译 |
The compilation function.
|
编译函数。 |
1260天前 |
|
翻译 |
177#翻译 |
As with filter registration, it is also possible to use ``register.tag`` as a
decorator in Python 2.4 and above:
|
和注册过滤器类似,也可以在Python2.4及其以上版本中使用 ``register.tag`` 修饰: |
1246天前 |
|
翻译 |
180#翻译 |
If you leave off the ``name`` argument, as in the second example, Django will
use the functions name as the tag name.
|
如果你像在第二个例子中那样忽略 ``name`` 参数的话,Django会使用函数名称作为标签名称。 |
1246天前 |
|
翻译 |
181#翻译 |
Setting a Variable in the Context
.................................
|
在上下文中设置变量
................................. |
1401天前 |
|
翻译 |
182#翻译 |
The previous sections example simply returned a value. Often its useful to set
template variables instead of returning values. That way, template authors can
just use the variables that your template tags set.
|
前一节的例子只是简单的返回一个值。很多时候设置一个模板变量而非返回值也很有用。那样,模板作者就只能使用你的模板标签所设置的变量。 |
1401天前 |
|
翻译 |
183#翻译 |
To set a variable in the context, use dictionary assignment on the context
object in the ``render()`` method. Heres an updated version of
``CurrentTimeNode`` that sets a template variable, ``current_time`` , instead
of returning it:
|
要在上下文中设置变量,在 ``render()`` 函数的context对象上使用字典赋值。这里是一个修改过的 ``CurrentTimeNode`` ,其中设定了一个模板变量 ``current_time`` ,并没有返回它: |
1247天前 |
|
翻译 |
186#翻译 |
Note that ``render()`` returns an empty string. ``render()`` should always
return a string, so if all the template tag does is set a variable,
``render()`` should return an empty string.
|
注意 ``render()`` 返回了一个空字符串。 ``render()`` 应当总是返回一个字符串,所以如果模板标签只是要设置变量, ``render()`` 就应该返回一个空字符串。
|
1247天前 |
|
翻译 |
187#翻译 |
Heres how youd use this new version of the tag:
|
你应该这样使用这个新版本的标签:
|
1247天前 |
|
翻译 |
190#翻译 |
But theres a problem with ``CurrentTimeNode2`` : the variable name
``current_time`` is hard-coded. This means youll need to make sure your
template doesnt use ``{{ current_time }}`` anywhere else, because ``{%
current_time2 %}`` will blindly overwrite that variables value.
|
但是 ``CurrentTimeNode2`` 有一个问题: 变量名 ``current_time`` 是硬编码的。这意味着你必须确定你的模板在其它任何地方都不使用 ``{{ current_time }}`` ,因为 ``{% current_time2 %}`` 会盲目的覆盖该变量的值。
|
1247天前 |
|
翻译 |
191#翻译 |
A cleaner solution is to make the template tag specify the name of the variable
to be set, like so:
|
一种更简洁的方案是由模板标签来指定需要设定的变量的名称,就像这样: |
1247天前 |
|
翻译 |
194#翻译 |
To do so, youll need to refactor both the compilation function and the ``Node``
class, as follows:
|
为此,你需要重构编译函数和 ``Node`` 类,如下所示:
|
1247天前 |
|
翻译 |
197#翻译 |
Now ``do_current_time()`` passes the format string and the variable name to
``CurrentTimeNode3`` .
|
现在 ``do_current_time()`` 把格式字符串和变量名传递给 ``CurrentTimeNode3`` 。 |
1246天前 |
|
翻译 |
198#翻译 |
Parsing Until Another Block Tag
...............................
|
分析直至另一个块标签
...............................
|
1314天前 |
|
翻译 |
199#翻译 |
Template tags can work as blocks containing other tags (think ``{% if %}`` ,
``{% for %}`` , etc.). To create a template tag like this, use
``parser.parse()`` in your compilation function.
|
模板标签可以像包含其它标签的块一样工作(想想 ``{% if %}`` 、 ``{% for %}`` 等)。 要创建一个这样的模板标签,在你的编译函数中使用 ``parser.parse()`` 。
|
1246天前 |
|
翻译 |
200#翻译 |
Heres how the standard ``{% comment %}`` tag is implemented:
|
标准的 ``{% comment %}`` 标签是这样实现的: |
1246天前 |
|
翻译 |
203#翻译 |
``parser.parse()`` takes a tuple of names of block tags to parse until. It
returns an instance of ``django.template.NodeList`` , which is a list of all
``Node`` objects that the parser encountered *before* it encountered any of the
tags named in the tuple.
|
``parser.parse()`` 接收一个包含了需要分析块标签名的元组作为参数. 它返回一个 ``django.template.NodeList`` 实例, 它是一个包含了所有 ``Node`` 对象的列表,这些对象代表了分析器在遇到元组中任一标签名之 *前* 的内容.
|
1314天前 |
|
翻译 |
204#翻译 |
So in the preceding example, ``nodelist`` is a list of all nodes between ``{%
comment %}`` and ``{% endcomment %}`` , not counting ``{% comment %}`` and ``{%
endcomment %}`` themselves.
|
因此在前面的例子中, ``nodelist`` 是在 ``{% comment %}`` 和 ``{% endcomment %}`` 之间所有节点的列表,不包括 ``{% comment %}`` 和 ``{% endcomment %}`` 自身。
|
1246天前 |
|
翻译 |
205#翻译 |
After ``parser.parse()`` is called, the parser hasnt yet consumed the ``{%
endcomment %}`` tag, so the code needs to explicitly call
``parser.delete_first_token()`` to prevent that tag from being processed twice.
|
在 ``parser.parse()`` 被调用之后,分析器还没有清除 ``{% endcomment %}`` 标签,因此代码需要显式地调用 ``parser.delete_first_token()`` 来防止该标签被处理两次。
|
1246天前 |
|
翻译 |
206#翻译 |
Then ``CommentNode.render()`` simply returns an empty string. Anything between
``{% comment %}`` and ``{% endcomment %}`` is ignored.
|
之后 ``CommentNode.render()`` 只是简单地返回一个空字符串。在 ``{% comment %}`` 和 ``{% endcomment %}`` 之间的所有内容都被忽略。
|
1246天前 |
|
翻译 |
207#翻译 |
Parsing Until Another Block Tag and Saving Contents
...................................................
|
分析直至另外一个块标签并保存内容
...................................................
|
1314天前 |
|
翻译 |
208#翻译 |
In the previous example, ``do_comment()`` discarded everything between ``{%
comment %}`` and ``{% endcomment %}`` . Its also possible to do something with
the code between block tags instead.
|
在前一个例子中, ``do_comment()`` 抛弃了在 ``{% comment %}`` 和 ``{% endcomment %}`` 之间的所有内容。同样,也可以对块标签之间的代码进行处理。
|
1246天前 |
|
翻译 |
209#翻译 |
For example, heres a custom template tag, ``{% upper %}`` , that capitalizes
everything between itself and ``{% endupper %}`` :
|
例如,这个自定义模板标签: ``{% upper %}`` ,它把自己和 ``{% endupper %}`` 之间的所有内容都变成大写:
|
1246天前 |
|
翻译 |
212#翻译 |
As in the previous example, well use ``parser.parse()`` . This time, we pass
the resulting ``nodelist`` to ``Node`` :
|
就像前面的例子一样,我们将使用 ``parser.parse()`` 。这次,我们将产生的 ``nodelist`` 传递给 ``Node`` : |
1246天前 |
|
翻译 |
215#翻译 |
The only new concept here is ``self.nodelist.render(context)`` in
``UpperNode.render()`` . This simply calls ``render()`` on each ``Node`` in the
node list.
|
这里唯一的一个新概念是 ``UpperNode.render()`` 中的 ``self.nodelist.render(context)`` 。它对节点列表中的每个 ``Node`` 简单的调用 ``render()`` 。 |
1246天前 |
|
翻译 |
216#翻译 |
For more examples of complex rendering, see the source code for ``{% if %}`` ,
``{% for %}`` , ``{% ifequal %}`` , and ``{% ifchanged %}`` . They live in
``django/template/defaulttags.py`` .
|
更多的复杂渲染示例请查看 ``django/template/defaulttags.py`` 中的 ``{% if %}`` 、 ``{% for %}`` 、 ``{% ifequal %}`` 和 ``{% ifchanged %}`` 的代码。
|
1246天前 |
|
翻译 |
217#翻译 |
Shortcut for Simple Tags
''''''''''''''''''''''''
|
简单标签的快捷方式
''''''''''''''''''' |
1472天前 |
|
翻译 |
218#翻译 |
Many template tags take a single argumenta string or a template variable
referenceand return a string after doing some processing based solely on the
input argument and some external information. For example, the ``current_time``
tag we wrote earlier is of this variety. We give it a format string, and it
returns the time as a string.
|
许多模板标签接收单一的字符串参数或者一个模板变量
引用,然后独立地根据输入变量和一些其它外部信息进行处理并返回一个字符串. 例如, 我们先前写的 ``current_time``
标签就是这样一个例子. 我们给它格式字符串, 然后它把时间作为字符串返回.
|
1314天前 |
|
翻译 |
219#翻译 |
To ease the creation of these types of tags, Django provides a helper function,
``simple_tag`` . This function, which is a method of
``django.template.Library`` , takes a function that accepts one argument, wraps
it in a ``render`` function and the other necessary bits mentioned previously,
and registers it with the template system.
|
为了简化这类标签,Django 提供了一个帮助函数: ``simple_tag`` 。这个函数是 ``django.template.Library`` 的一个方法,它接受一个只有一个参数的函数作参数,把它包装在 ``render`` 函数和之前提及过的其他的必要单位中,然后通过模板系统注册标签。
|
1246天前 |
|
翻译 |
220#翻译 |
Our earlier ``current_time`` function could thus be written like this:
|
我们之前的的 ``current_time`` 函数于是可以写成这样:
|
1246天前 |
|
翻译 |
223#翻译 |
In Python 2.4, the decorator syntax also works:
|
在Python 2.4中,也可以使用修饰语法: |
1246天前 |
|
翻译 |
226#翻译 |
A couple of things to notice about the ``simple_tag`` helper function are as
follows:
|
有关 ``simple_tag`` 辅助函数,需要注意下面一些事情: |
1246天前 |
|
翻译 |
227#翻译 |
* Only the (single) argument is passed into our function.
|
* 传递给我们的函数的只有(单个)参数。 |
1246天前 |
|
翻译 |
228#翻译 |
* Checking for the required number of arguments has already been done by the
time our function is called, so we dont need to do that.
|
* 在我们的函数被调用的时候,检查必需参数个数的工作已经完成了,所以我们不需要再做这个工作。
|
1246天前 |
|
翻译 |
229#翻译 |
* The quotes around the argument (if any) have already been stripped away, so
we receive a plain string.
|
* 参数两边的引号(如果有的话)已经被截掉了,所以我们会接收到一个普通字符串。
|
1246天前 |
|
翻译 |
230#翻译 |
Inclusion Tags
''''''''''''''
|
包含标签
''''''''''''''
|
1314天前 |
|
翻译 |
231#翻译 |
Another common template tag is the type that displays some data by rendering
*another* template. For example, Djangos admin interface uses custom template
tags to display the buttons along the bottom of the add/change form pages.
Those buttons always look the same, but the link targets change depending on
the object being edited. Theyre a perfect case for using a small template that
is filled with details from the current object.
|
另外一类常用的模板标签是通过渲染 *其他* 模板显示数据的。比如说,Django的后台管理界面,它使用了自定义的模板标签来显示新增/编辑表单页面下部的按钮。那些按钮看起来总是一样的,但是链接却随着所编辑的对象的不同而改变。这就是一个使用小模板很好的例子,这些小模板就是当前对象的详细信息。
|
1246天前 |
|
翻译 |
232#翻译 |
These sorts of tags are called *inclusion tags* . Writing inclusion tags is
probably best demonstrated by example. Lets write a tag that produces a list of
choices for a simple multiple-choice ``Poll`` object. Well use the tag like
this:
|
这些排序标签被称为 *包含标签* 。如何写包含标签最好通过举例来说明。我们来写一个可以生成一个选项列表的多选项对象 ``Poll`` 。标签这样使用: |
1246天前 |
|
翻译 |
235#翻译 |
The result will be something like this:
|
结果将会像下面这样: |
1472天前 |
|
翻译 |
238#翻译 |
First, we define the function that takes the argument and produces a dictionary
of data for the result. Notice that we need to return only a dictionary, not
anything more complex. This will be used as the context for the template
fragment:
|
首先,我们定义一个函数,通过给定的参数生成一个字典形式的结果。
需要注意的是,我们只需要返回字典类型的结果就行了,它将被用做模板片断的context。
(译注:dict 的 key 作为变量名在模板中被使用) |
1246天前 |
|
翻译 |
241#翻译 |
Next, we create the template used to render the tags output. Following our
example, the template is very simple:
|
接下来,我们创建用于渲染标签输出的模板。在我们的例子中,模板很简单: |
1246天前 |
|
翻译 |
244#翻译 |
Finally, we create and register the inclusion tag by calling the
``inclusion_tag()`` method on a ``Library`` object.
|
最后,我们通过对一个 ``Library`` 对象使用 ``inclusion_tag()`` 方法来创建并注册这个包含标签。
|
1246天前 |
|
翻译 |
245#翻译 |
Following our example, if the preceding template is in a file called
``polls/result_snippet.html`` , we register the tag like this:
|
在我们的例子中,如果先前的模板在 ``polls/result_snippet.html`` 文件中,那么我们这样注册标签: |
1246天前 |
|
翻译 |
248#翻译 |
As always, Python 2.4 decorator syntax works as well, so we could have instead
written this:
|
和往常一样,我们也可以使用Python 2.4中的修饰语法,所以我们还可以这么写: |
1246天前 |
|
翻译 |
251#翻译 |
Sometimes, your inclusion tags need access to values from the parent templates
context. To solve this, Django provides a ``takes_context`` option for
inclusion tags. If you specify ``takes_context`` in creating a template tag,
the tag will have no required arguments, and the underlying Python function
will have one argument: the template context as of when the tag was called.
|
有时候,你的包含标签需要访问父模板的context。为了解决这个问题,Django提供了一个 ``takes_context`` 选项。如果你在创建模板标签时,指明了这个选项,这个标签就不需要参数,并且下面的Python函数会带一个参数:就是当这个标签被调用时的模板context。 |
1246天前 |
|
翻译 |
252#翻译 |
For example, say youre writing an inclusion tag that will always be used in a
context that contains ``home_link`` and ``home_title`` variables that point
back to the main page. Heres what the Python function would look like:
|
例如,你正在写一个包含标签,该标签包含有指向主页的 ``home_link`` 和 ``home_title`` 变量。Python函数会像这样: |
1260天前 |
|
翻译 |
255#翻译 |
Note
|
备注 |
1472天前 |
|
翻译 |
256#翻译 |
The first parameter to the function *must* be called ``context`` .
|
函数的第一个参数 *必须* 是 ``context`` 。 |
1282天前 |
|
翻译 |
257#翻译 |
The template ``link.html`` might contain the following:
|
模板 ``link.html`` 可能包含下面的东西: |
1260天前 |
|
翻译 |
260#翻译 |
Then, anytime you want to use that custom tag, load its library and call it
without any arguments, like so:
|
然后您想使用自定义标签时,就可以加载它的库,然后不带参数地调用它,就像这样:
|
1246天前 |
|
翻译 |
263#翻译 |
Writing Custom Template Loaders
```````````````````````````````
|
编写自定义模板加载器
```````````````````` |
1246天前 |
|
翻译 |
264#翻译 |
Djangos built-in template loaders (described in the Inside Template Loading
section above) will usually cover all your template-loading needs, but its
pretty easy to write your own if you need special loading logic. For example,
you could load templates from a database, or directly from a Subversion
repository using Subversions Python bindings, or (as shown shortly) from a ZIP
archive.
|
Djangos 内置的模板加载器(在先前的模板加载内幕章节有叙述)通常会满足你的所有的模板加载需求,但是如果你有特殊的加载需求的话,编写自己的模板加载器也会相当简单。比如:你可以从数据库加载模板,或者使用 Subversions的Python实现直接从Subversion库加载模板,再或者(稍后展示)从zip文件加载模板。
|
1246天前 |
|
翻译 |
265#翻译 |
A template loaderthat is, each entry in the ``TEMPLATE_LOADERS`` setting is
expected to be a callable with this interface:
|
一个模板加载器,也就是 ``TEMPLATE_LOADERS`` 中的每一项,都要能被下面这个接口所调用: |
1276天前 |
|
翻译 |
268#翻译 |
The ``template_name`` argument is the name of the template to load (as passed
to ``loader.get_template()`` or ``loader.select_template()`` ), and
``template_dirs`` is an optional list of directories to search instead of
``TEMPLATE_DIRS`` .
|
参数 ``template_name`` 是所加载模板的名称 (和传递给 ``loader.get_template()`` 或者 ``loader.select_template()`` 一样), 而
``template_dirs`` 是一个可选的包含除去 ``TEMPLATE_DIRS`` 之外的搜索目录列表。
|
1380天前 |
|
翻译 |
269#翻译 |
If a loader is able to successfully load a template, it should return a tuple:
``(template_source, template_path)`` . Here, ``template_source`` is the
template string that will be compiled by the template engine, and
``template_path`` is the path the template was loaded from. That path might be
shown to the user for debugging purposes, so it should quickly identify where
the template was loaded from.
|
如果加载器能够成功加载一个模板, 它应当返回一个元组: ``(template_source, template_path)`` 。在这里的 ``template_source`` 就是将被模板引擎编译的的模板字符串,而 ``template_path`` 是被加载的模板的路径。由于那个路径可能会出于调试目的显示给用户,因此它应当很快的指明模板从哪里加载而来。
|
792天前 |
|
翻译 |
270#翻译 |
If the loader is unable to load a template, it should raise
``django.template.TemplateDoesNotExist`` .
|
如果加载器加载模板失败,那么就会触发 ``django.template.TemplateDoesNotExist`` 异常。 |
1246天前 |
|
翻译 |
271#翻译 |
Each loader function should also have an ``is_usable`` function attribute. This
is a Boolean that informs the template engine whether this loader is available
in the current Python installation. For example, the eggs loader (which is
capable of loading templates from Python eggs) sets ``is_usable`` to ``False``
if the ``pkg_resources`` module isnt installed, because ``pkg_resources`` is
necessary to read data from eggs.
|
每个加载函数都应该有一个名为 ``is_usable`` 的函数属性。这个属性是一个布尔值,用于告知模板引擎这个加载器是否在当前安装的Python中可用。例如,如果 ``pkg_resources`` 模块没有安装的话,eggs加载器(它能够从python eggs中加载模板)就应该把 ``is_usable`` 设为 ``False`` ,因为必须通过 ``pkg_resources`` 才能从eggs中读取数据。
|
1246天前 |
|
翻译 |
272#翻译 |
An example should help clarify all of this. Heres a template loader function
that can load templates from a ZIP file. It uses a custom setting,
``TEMPLATE_ZIP_FILES`` , as a search path instead of ``TEMPLATE_DIRS`` , and it
expects each item on that path to be a ZIP file containing templates:
|
一个例子可以清晰地阐明一切。这儿是一个模板加载函数,它可以从ZIP文件中加载模板。它使用了自定义的设置 ``TEMPLATE_ZIP_FILES`` 来取代了 ``TEMPLATE_DIRS`` 用作查找路径,并且它假设在此路径上的每一个文件都是包含模板的ZIP文件: |
1276天前 |
|
翻译 |
275#翻译 |
The only step left if we want to use this loader is to add it to the
``TEMPLATE_LOADERS`` setting. If we put this code in a package called
``mysite.zip_loader`` , then we add ``mysite.zip_loader.load_template_source``
to ``TEMPLATE_LOADERS`` .
|
我们要想使用它,还差最后一步,就是把它加入到 ``TEMPLATE_LOADERS`` 。如果我们把这部分代码放到一个叫做 ``mysite.zip_loader`` 的包中,我们就需要把 ``mysite.zip_loader.load_template_source`` 加入到 ``TEMPLATE_LOADERS`` 中去。 |
1260天前 |
|
翻译 |
276#翻译 |
Using the Built-in Template Reference
`````````````````````````````````````
|
使用内置的模板参考
````````````````````````````````````` |
1398天前 |
|
翻译 |
277#翻译 |
Djangos admin interface includes a complete reference of all template tags and
filters available for a given site. Its designed to be a tool that Django
programmers give to template developers. To see it, go to the admin interface
and click the Documentation link at the upper right of the page.
|
Django管理界面包含一个完整的参考资料,里面有所有的可以在特定网站上使用的模板标签和过滤器。它设计的初衷是Django程序员提供给模板开发人员的一个工具。你可以点击管理页面右上角的文档链接来查看这些资料。 |
1246天前 |
|
翻译 |
278#翻译 |
The reference is divided into four sections: tags, filters, models, and views.
The *tags* and *filters* sections describe all the built-in tags (in fact, the
tag and filter references in Chapter 4 come directly from those pages) as well
as any custom tag or filter libraries available.
|
参考说明分为4个部分:标签、过滤器、模型和视图。 *标签* 和 *过滤器* 部分描述了所有内置的标签(实际上,第4章中用到的标签和过滤器都直接来源于那几页)以及一些可用的自定义标签和过滤器库。 |
1276天前 |
|
翻译 |
279#翻译 |
The *views* page is the most valuable. Each URL in your site has a separate
entry here. If the related view includes a docstring, clicking the URL will
show you the following:
|
*视图* 页面是最有价值的。网站中的每个URL都在这儿有独立的入口。如果相关的视图包含一个 文档字符串, 点击URL,你就会看到: |
1276天前 |
|
翻译 |
280#翻译 |
* The name of the view function that generates that view
|
* 生成本视图的视图函数的名字 |
1246天前 |
|
翻译 |
281#翻译 |
* A short description of what the view does
|
* 视图功能的一个简短描述 |
1246天前 |
|
翻译 |
282#翻译 |
* The context, or a list of variables available in the views template
|
* 上下文或一个视图模板中可用的变量的列表 |
1246天前 |
|
翻译 |
283#翻译 |
* The name of the template or templates that are used for that view
|
* 视图使用的模板的名字 |
1246天前 |
|
翻译 |
284#翻译 |
For a detailed example of view documentation, read the source code for Djangos
generic ``object_list`` view, which is in
``django/views/generic/list_detail.py`` .
|
要想查看关于视图文档的更详细的例子,请阅读Django的通用 ``object_list`` 视图部分的源代码,它位于 ``django/views/generic/list_detail.py`` 文件中。 |
1246天前 |
|
翻译 |
285#翻译 |
Because Django-powered sites usually use database objects, the *models* pages
describe each type of object in the system along with all the fields available
on that object.
|
通常情况下,由Django构建的网站都会使用数据库对象, *模型* 页面描述了系统中所有类型的对象,以及该对象对应的所有可用字段。 |
1246天前 |
|
翻译 |
286#翻译 |
Taken together, the documentation pages should tell you every tag, filter,
variable, and object available to you in a given template.
|
总之,这些文档告诉你在模板中的所有可用的标签、过滤器、变量和对象。 |
1246天前 |
|
翻译 |
287#翻译 |
Configuring the Template System in Standalone Mode
``````````````````````````````````````````````````
|
配置独立模式下的模板系统
```````````````````````` |
1247天前 |
|
翻译 |
288#翻译 |
Note
|
备注 |
1472天前 |
|
翻译 |
289#翻译 |
This section is only of interest to people trying to use the template system as
an output component in another application. If you are using the template
system as part of a Django application, the information presented here doesnt
apply to you.
|
这部分只针对于对在其他应用中使用模版系统作为输出组件感兴趣的人。如果你是在Django应用中使用模版系统,请略过此部分。 |
1298天前 |
|
翻译 |
290#翻译 |
Normally, Django will load all the configuration information it needs from its
own default configuration file, combined with the settings in the module given
in the ``DJANGO_SETTINGS_MODULE`` environment variable. But if youre using the
template system independently of the rest of Django, the environment variable
approach isnt very convenient, because you probably want to configure the
template system in line with the rest of your application rather than dealing
with settings files and pointing to them via environment variables.
|
通常,Django会从它的默认配置文件和由 ``DJANGO_SETTINGS_MODULE`` 环境变量所指定的模块中加载它需要的所有配置信息。但是当你想在非Django应用中使用模版系统的时候,采用环境变量并不是很好的方法。比起为模版系统单独采用配置文件并用环境变量来指向它,你可能更希望能够在你的应用中采用一致的配置方法来配置模版系统和其他部分 |
1298天前 |
|
翻译 |
291#翻译 |
To solve this problem, you need to use the manual configuration option
described fully Appendix E. In a nutshell, you need to import the appropriate
pieces of the template system and then, *before* you call any of the template
functions, call ``django.conf.settings.configure()`` with any settings you wish
to specify.
|
为了解决这个问题,你需要使用附录E中所描述的手动配置选项。简单来说,你需要引入合适的模板系统,并且在调用任何模板函数 *之前* 调用 ``django.conf.settings.configure()`` 来指定任何你想要的设置。 |
1276天前 |
|
翻译 |
292#翻译 |
You might want to consider setting at least ``TEMPLATE_DIRS`` (if you are going
to use template loaders), ``DEFAULT_CHARSET`` (although the default of
``utf-8`` is probably fine), and ``TEMPLATE_DEBUG`` . All available settings
are described in Appendix E, and any setting starting with ``TEMPLATE_`` is of
obvious interest.
|
你可能会考虑至少要设置 ``TEMPLATE_DIRS`` (如果你打算使用模板加载器), ``DEFAULT_CHARSET`` (尽管默认的 ``utf-8`` 编码相当好用),以及 ``TEMPLATE_DEBUG`` 。所有可用的选项都在附录E中详细描述,所有以 ``TEMPLATE_`` 开头的选项都可能使你感兴趣的。 |
1246天前 |
|
翻译 |
293#翻译 |
Whats Next
``````````
|
接下来?
```````` |
1247天前 |
|
翻译 |
294#翻译 |
So far this book has assumed that the content youre displaying is HTML. This
isnt a bad assumption for a book about Web development, but at times youll want
to use Django to output other data formats.
|
迄今为止,本书假定您想展示的内容为HTML。对于一个有关Web开发的书来说,这不是一个
不好的假设,但有时你想用Django输出其他数据格式。 |
1472天前 |
|
翻译 |
295#翻译 |
The next chapter describes how you can use Django to produce images, PDFs, and
any other data format you can imagine.
|
下一章将讲解如何使用Django生成图像、PDF、还有你可以想到的其他数据格式。 |
1246天前 |
|
翻译 |