diff --git a/django/contrib/comments/templates/comments/list.html b/django/contrib/comments/templates/comments/list.html new file mode 100644 index 0000000000..3d4ec1ed8f --- /dev/null +++ b/django/contrib/comments/templates/comments/list.html @@ -0,0 +1,10 @@ +
+ {% for comment in comment_list %} +
+ {{ comment.submit_date }} - {{ comment.name }} +
+
+

{{ comment.comment }}

+
+ {% endfor %} +
diff --git a/django/contrib/comments/templatetags/comments.py b/django/contrib/comments/templatetags/comments.py index 1ebc9dba34..8e62f91eed 100644 --- a/django/contrib/comments/templatetags/comments.py +++ b/django/contrib/comments/templatetags/comments.py @@ -81,10 +81,10 @@ class BaseCommentNode(template.Node): object_pk = smart_unicode(object_pk), site__pk = settings.SITE_ID, ) - + # The is_public and is_removed fields are implementation details of the # built-in comment model's spam filtering system, so they might not - # be present on a custom comment model subclass. If they exist, we + # be present on a custom comment model subclass. If they exist, we # should filter on them. field_names = [f.name for f in self.comment_model._meta.fields] if 'is_public' in field_names: @@ -169,6 +169,46 @@ class RenderCommentFormNode(CommentFormNode): else: return '' +class RenderCommentListNode(CommentListNode): + """Render the comment list directly""" + + #@classmethod + def handle_token(cls, parser, token): + """Class method to parse render_comment_list and return a Node.""" + tokens = token.contents.split() + if tokens[1] != 'for': + raise template.TemplateSyntaxError("Second argument in %r tag must be 'for'" % tokens[0]) + + # {% render_comment_list for obj %} + if len(tokens) == 3: + return cls(object_expr=parser.compile_filter(tokens[2])) + + # {% render_comment_list for app.models pk %} + elif len(tokens) == 4: + return cls( + ctype = BaseCommentNode.lookup_content_type(tokens[2], tokens[0]), + object_pk_expr = parser.compile_filter(tokens[3]) + ) + handle_token = classmethod(handle_token) + + def render(self, context): + ctype, object_pk = self.get_target_ctype_pk(context) + if object_pk: + template_search_list = [ + "comments/%s/%s/list.html" % (ctype.app_label, ctype.model), + "comments/%s/list.html" % ctype.app_label, + "comments/list.html" + ] + qs = self.get_query_set(context) + context.push() + liststr = render_to_string(template_search_list, { + "comment_list" : self.get_context_value_from_queryset(context, qs) + }, context) + context.pop() + return liststr + else: + return '' + # We could just register each classmethod directly, but then we'd lose out on # the automagic docstrings-into-admin-docs tricks. So each node gets a cute # wrapper function that just exists to hold the docstring. @@ -216,6 +256,24 @@ def get_comment_list(parser, token): """ return CommentListNode.handle_token(parser, token) +#@register.tag +def render_comment_list(parser, token): + """ + Render the comment list (as returned by ``{% get_comment_list %}``) + through the ``comments/list.html`` template + + Syntax:: + + {% render_comment_list for [object] %} + {% render_comment_list for [app].[model] [object_id] %} + + Example usage:: + + {% render_comment_list for event %} + + """ + return RenderCommentListNode.handle_token(parser, token) + #@register.tag def get_comment_form(parser, token): """ @@ -271,4 +329,5 @@ register.tag(get_comment_list) register.tag(get_comment_form) register.tag(render_comment_form) register.simple_tag(comment_form_target) -register.simple_tag(get_comment_permalink) \ No newline at end of file +register.simple_tag(get_comment_permalink) +register.tag(render_comment_list) diff --git a/docs/ref/contrib/comments/example.txt b/docs/ref/contrib/comments/example.txt index 626e8b4a95..e9445353ca 100644 --- a/docs/ref/contrib/comments/example.txt +++ b/docs/ref/contrib/comments/example.txt @@ -39,6 +39,18 @@ available in the context, then you can refer to it directly:: {% get_comment_count for entry as comment_count %}

{{ comment_count }} comments have been posted.

+Next, we can use the :ttag:`render_comment_list` tag, to render all comments +to the given instance (``entry``) by using the ``comments/list.html`` template. + + {% render_comment_list for entry %} + +Django will will look for the ``list.html`` under the following directories +(for our example):: + + comments/blog/post/list.html + comments/blog/list.html + comments/list.html + To get a list of comments, we make use of the :ttag:`get_comment_list` tag. This tag's usage is very similar to the :ttag:`get_comment_count` tag. We need to remember that the :ttag:`get_comment_list` returns a list of comments @@ -58,7 +70,7 @@ display the comments template available under your ``comments/form.html``. The other method gives you a chance to customize the form. The first method makes use of the :ttag:`render_comment_form` tag. It's usage -too is similar to the other two tags we have discussed above:: +too is similar to the other three tags we have discussed above:: {% render_comment_form for entry %} @@ -74,6 +86,7 @@ tag called :ttag:`comment_form_target`. This tag on rendering gives the URL where the comment form is posted. Without any :ref:`customization `, :ttag:`comment_form_target` evaluates to ``/comments/post/``. We use this tag in the form's ``action`` attribute. + The :ttag:`get_comment_form` tag renders a ``form`` for a model instance by creating a context variable. One can iterate over the ``form`` object to get individual fields. This gives you fine-grain control over the form:: diff --git a/docs/ref/contrib/comments/index.txt b/docs/ref/contrib/comments/index.txt index f66d14d0c4..9f53f06299 100644 --- a/docs/ref/contrib/comments/index.txt +++ b/docs/ref/contrib/comments/index.txt @@ -84,11 +84,34 @@ different ways you can specify which object to attach to: In the above, ``blog.entry`` is the app label and (lower-cased) model name of the model class. -.. templatetag:: get_comment_list - Displaying comments ------------------- +To display a list of comments, you can use the template tags +:ttag:`render_comment_list` or :ttag:`get_comment_list`. + +.. templatetag:: render_comment_list + +Quickly rendering a comment list +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The easiest way to display a list of comments for some object is by using +:ttag:`render_comment_list`:: + + {% render_comment_list for [object] %} + +For example:: + + {% render_comment_list for event %} + +This will render comments using a template named ``comments/list.html``, a +default version of which is included with Django. + +.. templatetag:: get_comment_list + +Rendering a custom comment list +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + To get the list of comments for some object, use :ttag:`get_comment_list`:: {% get_comment_list for [object] as [varname] %} diff --git a/tests/regressiontests/comment_tests/tests/templatetag_tests.py b/tests/regressiontests/comment_tests/tests/templatetag_tests.py index 7cb2148b54..669caff667 100644 --- a/tests/regressiontests/comment_tests/tests/templatetag_tests.py +++ b/tests/regressiontests/comment_tests/tests/templatetag_tests.py @@ -83,4 +83,15 @@ class CommentTemplateTagTests(CommentTestCase): ctx, out = self.render(t, author=author) self.assertEqual(out, "/cr/%s/%s/#c2-by-Joe Somebody" % (ct.id, author.id)) + def testRenderCommentList(self, tag=None): + t = "{% load comments %}" + (tag or "{% render_comment_list for comment_tests.article a.id %}") + ctx, out = self.render(t, a=Article.objects.get(pk=1)) + self.assert_(out.strip().startswith("
")) + self.assert_(out.strip().endswith("
")) + + def testRenderCommentListFromLiteral(self): + self.testRenderCommentList("{% render_comment_list for comment_tests.article 1 %}") + + def testRenderCommentListFromObject(self): + self.testRenderCommentList("{% render_comment_list for a %}")