Render forum posts as Markdown

Python · Django · intermediate · modification

Forum posts finally get formatting. A `render_markdown` filter turns the body into HTML with Python-Markdown, using the fenced code, tables and sane lists extensions so code samples and tables from other sites paste in cleanly. The post page swaps `linebreaks` for the new filter; replies keep `linebreaks` until the next PR. Tried it on a long post with headings, a code block and a table, and on an empty body.

Django 5.1 community forum, `USE_TZ = True`, sessions with `SESSION_COOKIE_HTTPONLY = True`, CSRF middleware on. No Content-Security-Policy header is set. The `forum` app already has `templatetags/forum_tags.py` (with `reply_label`) and is in `INSTALLED_APPS`; `Post.body` is a non-null `TextField` of up to 20,000 characters written by the post's author. Staff moderate posts from the same post page while signed in to the admin. `markdown` 3.7 and `nh3` 0.2 are already in `requirements.txt`.

Requirements

Files touched

--- forum/templatetags/forum_tags.py
+import markdown
 from django import template
+from django.utils.safestring import mark_safe
 
 register = template.Library()
+
+MARKDOWN_EXTENSIONS = ["fenced_code", "tables", "sane_lists"]
 
 
     return "1 reply" if count == 1 else f"{count} replies"
 
+
[email protected]
+def render_markdown(text):
+    """Render a post body written in Markdown to HTML."""
+    html = markdown.markdown(text, extensions=MARKDOWN_EXTENSIONS)
+    return mark_safe(html)
+
--- forum/templates/forum/post_detail.html
     <p class="post-meta">by {{ post.author.username }} · {{ post.reply_count|reply_label }}</p>
   </header>
-  <div class="post-body">{{ post.body|linebreaks }}</div>
+  <div class="post-body markdown">{{ post.body|render_markdown }}</div>
 </article>
 {% endblock %}

Review this PR

Python practice