Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Finished docs/templates_python.txt

git-svn-id: http://code.djangoproject.com/svn/django/trunk@628 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit cadb6a008d16720b0e7192ec698c3a43496f4984 1 parent 276731d
Adrian Holovaty authored

Showing 1 changed file with 85 additions and 11 deletions. Show diff stats Hide diff stats

  1. 96  docs/templates_python.txt
96  docs/templates_python.txt
@@ -478,10 +478,10 @@ responsible for returning a ``Node`` instance based on the contents of the tag.
478 478
 
479 479
 By convention, the name of each compilation function should start with ``do_``.
480 480
 
481  
-For example, let's write a template tag that displays the current date/time,
482  
-formatted according to a parameter given in the tag, in `strftime syntax`_.
483  
-It's a good idea to decide the tag syntax before anything else. In our case,
484  
-let's say the tag should be used like this::
  481
+For example, let's write a template tag, ``{% current_time %}``, that displays
  482
+the current date/time, formatted according to a parameter given in the tag, in
  483
+`strftime syntax`_. It's a good idea to decide the tag syntax before anything
  484
+else. In our case, let's say the tag should be used like this::
485 485
 
486 486
     <p>The time is {% current_time "%Y-%M-%d %I:%M %p" %}.</p>
487 487
 
@@ -507,10 +507,11 @@ Notes:
507 507
       example.
508 508
 
509 509
     * ``token.contents`` is a string of the raw contents of the tag. In our
510  
-      example, it's ``'current_time "%Y-%M-%d %I:%M %p"'``
  510
+      example, it's ``'current_time "%Y-%M-%d %I:%M %p"'``.
511 511
 
512  
-    * This function raises ``django.core.template.TemplateSyntaxError``, with
513  
-      helpful messages, for any syntax error.
  512
+    * This function is responsible for raising
  513
+      ``django.core.template.TemplateSyntaxError``, with helpful messages, for
  514
+      any syntax error.
514 515
 
515 516
     * The ``TemplateSyntaxError`` exceptions use the ``tag_name`` variable.
516 517
       Don't hard-code the tag's name in your error messages, because that
@@ -552,6 +553,9 @@ Notes:
552 553
 
553 554
     * The ``render()`` method is where the work actually happens.
554 555
 
  556
+    * ``render()`` should never raise ``TemplateSyntaxError`` or any other
  557
+      exception. It should fail silently, just as template filters should.
  558
+
555 559
 Ultimately, this decoupling of compilation and rendering results in an
556 560
 efficient template system, because a template can render multiple context
557 561
 without having to be parsed multiple times.
@@ -566,16 +570,16 @@ Finally, use a ``register_tag`` call, as in ``register_filter`` above. Example::
566 570
 
567 571
 ``register_tag`` takes two arguments:
568 572
 
569  
-    1. The name of the template tag -- a string
  573
+    1. The name of the template tag -- a string.
570 574
     2. The compilation function -- a Python function (not the name of the
571  
-       function as a string)
  575
+       function as a string).
572 576
 
573 577
 Setting a variable in the context
574 578
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
575 579
 
576 580
 The above example simply output a value. Generally, it's more flexible if your
577 581
 template tags set template variables instead of outputting values. That way,
578  
-you allow template authors to reuse the values that your template tags create.
  582
+template authors can reuse the values that your template tags create.
579 583
 
580 584
 To set a variable in the context, just use dictionary assignment on the context
581 585
 object in the ``render()`` method. Here's an updated version of
@@ -597,7 +601,7 @@ Here's how you'd use this new version of the tag::
597 601
 
598 602
     {% current_time "%Y-%M-%d %I:%M %p" %}<p>The time is {{ current_time }}.</p>
599 603
 
600  
-But, there's a naive problem with ``CurrentTimeNode2``: The variable name
  604
+But, there's a problem with ``CurrentTimeNode2``: The variable name
601 605
 ``current_time`` is hard-coded. This means you'll need to make sure your
602 606
 template doesn't use ``{{ current_time }}`` anywhere else, because the
603 607
 ``{% current_time %}`` will blindly overwrite that variable's value. A cleaner
@@ -636,3 +640,73 @@ class, like so::
636 640
 
637 641
 The difference here is that ``do_current_time()`` grabs the format string and
638 642
 the variable name, passing both to ``CurrentTimeNode3``.
  643
+
  644
+Parsing until another block tag
  645
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  646
+
  647
+Template tags can work in tandem. For instance, the standard ``{% comment %}``
  648
+tag hides everything until ``{% endcomment %}``. To create a template tag such
  649
+as this, use ``parser.parse()`` in your compilation function.
  650
+
  651
+Here's how the standard ``{% comment %}`` tag is implemented::
  652
+
  653
+    def do_comment(parser, token):
  654
+        nodelist = parser.parse(('endcomment',))
  655
+        parser.delete_first_token()
  656
+        return CommentNode()
  657
+
  658
+    class CommentNode(template.Node):
  659
+        def render(self, context):
  660
+            return ''
  661
+
  662
+``parser.parse()`` takes a tuple of names of block tags ''to parse until''. It
  663
+returns an instance of ``django.core.template.NodeList``, which is a list of
  664
+all ``Node`` objects that the parser encountered ''before'' it encountered
  665
+any of the tags named in the tuple.
  666
+
  667
+In ``"nodelist = parser.parse(('endcomment',))"`` in the above example,
  668
+``nodelist`` is a list of all nodes between the ``{% comment %}`` and
  669
+``{% endcomment %}``, not counting ``{% comment %}`` and ``{% endcomment %}``
  670
+themselves.
  671
+
  672
+After ``parser.parse()`` is called, the parser hasn't yet "consumed" the
  673
+``{% endcomment %}`` tag, so the code needs to explicitly call
  674
+``parser.delete_first_token()``.
  675
+
  676
+``CommentNode.render()`` simply returns an empty string. Anything between
  677
+``{% comment %}`` and ``{% endcomment %}`` is ignored.
  678
+
  679
+Parsing unitl another block tag, and saving contents
  680
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  681
+
  682
+In the previous example, ``do_comment()`` discarded everything between
  683
+``{% comment %}`` and ``{% endcomment %}``. Instead of doing that, it's
  684
+possible to do something with the code between block tags.
  685
+
  686
+For example, here's a custom template tag, ``{% upper %}``, that capitalizes
  687
+everything between itself and ``{% endupper %}``.
  688
+
  689
+Usage::
  690
+
  691
+    {% upper %}This will appear in uppercase, {{ your_name }}.{% endupper %}
  692
+
  693
+As in the previous example, we'll use ``parser.parse()``. But this time, we
  694
+pass the resulting ``nodelist`` to the ``Node``::
  695
+
  696
+    def do_upper(parser, token):
  697
+        nodelist = parser.parse(('endupper',))
  698
+        parser.delete_first_token()
  699
+        return UpperNode(nodelist)
  700
+
  701
+    class UpperNode(template.Node):
  702
+        def __init__(self, nodelist):
  703
+            self.nodelist = nodelist
  704
+        def render(self, context):
  705
+            output = self.nodelist.render(context)
  706
+            return output.upper()
  707
+
  708
+The only new concept here is the ``self.nodelist.render(context)`` in
  709
+``UpperNode.render()``.
  710
+
  711
+For more examples of complex rendering, see the source code for ``{% if %}``,
  712
+``{% for %}``, ``{% ifequal %}`` and ``{% ifchanged %}``.

0 notes on commit cadb6a0

Please sign in to comment.
Something went wrong with that request. Please try again.