Index: tracfullblog/core.py
===================================================================
--- tracfullblog/core.py	(revision 14870)
+++ tracfullblog/core.py	(working copy)
@@ -153,15 +153,15 @@
     def get_bloginfotext(self):
         """ Retrieves the blog info text in sidebar from database. """
         try:
-            cnx = self.env.get_db_cnx()
-            cursor = cnx.cursor()
-            cursor.execute("SELECT value from system " \
-                "WHERE name='fullblog_infotext'")
-            rows = cursor.fetchall()
-            if rows:
-                return rows[0][0] # Only item in cursor (hopefully)
-            else:
-                return ''
+            with self.env.db_query as cnx:
+                cursor = cnx.cursor()
+                cursor.execute("SELECT value from system " \
+                    "WHERE name='fullblog_infotext'")
+                rows = cursor.fetchall()
+                if rows:
+                    return rows[0][0] # Only item in cursor (hopefully)
+                else:
+                    return ''
         except:
             return ''
 
@@ -168,11 +168,10 @@
     def set_bloginfotext(self, text=''):
         """ Stores the blog info text in the database. """
         try:
-            cnx = self.env.get_db_cnx()
-            cursor = cnx.cursor()
-            cursor.execute("UPDATE system set value=%s " \
-                "WHERE name=%s", (text, 'fullblog_infotext'))
-            cnx.commit()
+            with self.env.db_transaction as cnx:
+                cursor = cnx.cursor()
+                cursor.execute("UPDATE system set value=%s " \
+                    "WHERE name=%s", (text, 'fullblog_infotext'))
             return True
         except:
             return False
Index: tracfullblog/model.py
===================================================================
--- tracfullblog/model.py	(revision 14870)
+++ tracfullblog/model.py	(working copy)
@@ -37,24 +37,24 @@
     Returns a list of tuples with:
         (name, version, publish_time, author, title, body) """
     assert terms
-    cnx = env.get_db_cnx()
-    cursor = cnx.cursor()
-    # SQL
-    columns = ['bp1.name', 'bp1.title', 'bp1.body',
-               'bp1.author', 'bp1.categories']
-    search_clause, args = search_to_sql(cnx, columns, terms)
-    sql = "SELECT bp1.name, bp1.version, bp1.publish_time, bp1.author, " \
-               "bp1.title, bp1.body " \
-               "FROM fullblog_posts bp1," \
-               "(SELECT name, max(version) AS ver " \
-               "FROM fullblog_posts GROUP BY name) bp2 " \
-               "WHERE bp1.version = bp2.ver AND bp1.name = bp2.name " \
-               "AND " + search_clause
-    env.log.debug("search_blog_posts() SQL: %r" % sql)
-    cursor.execute(sql, args)
-    # Return the items we have found
-    return [(row[0], row[1], to_datetime(row[2], utc), row[3],
-            row[4], row[5]) for row in cursor]
+    with env.db_query as cnx:
+        cursor = cnx.cursor()
+        # SQL
+        columns = ['bp1.name', 'bp1.title', 'bp1.body',
+                   'bp1.author', 'bp1.categories']
+        search_clause, args = search_to_sql(cnx, columns, terms)
+        sql = "SELECT bp1.name, bp1.version, bp1.publish_time, bp1.author, " \
+                   "bp1.title, bp1.body " \
+                   "FROM fullblog_posts bp1," \
+                   "(SELECT name, max(version) AS ver " \
+                   "FROM fullblog_posts GROUP BY name) bp2 " \
+                   "WHERE bp1.version = bp2.ver AND bp1.name = bp2.name " \
+                   "AND " + search_clause
+        env.log.debug("search_blog_posts() SQL: %r" % sql)
+        cursor.execute(sql, args)
+        # Return the items we have found
+        return [(row[0], row[1], to_datetime(row[2], utc), row[3],
+                row[4], row[5]) for row in cursor]
 
 def search_blog_comments(env, terms):
     """ Free text search for content of blog posts.
@@ -62,18 +62,18 @@
     Returns a list of tuples with:
         (post_name, comment_number, comment, comment_author, comment_time) """
     assert terms
-    cnx = env.get_db_cnx()
-    cursor = cnx.cursor()
-    # SQL
-    columns = ['author', 'comment']
-    search_clause, args = search_to_sql(cnx, columns, terms)
-    sql = "SELECT name, number, comment, author, time " \
-          "FROM fullblog_comments WHERE " + search_clause
-    env.log.debug("search_blog_comments() SQL: %r" % sql)
-    cursor.execute(sql, args)
-    # Return the items we have found
-    return [(row[0], row[1], row[2], row[3], to_datetime(row[4], utc))
-            for row in cursor]
+    with env.db_query as cnx:
+        cursor = cnx.cursor()
+        # SQL
+        columns = ['author', 'comment']
+        search_clause, args = search_to_sql(cnx, columns, terms)
+        sql = "SELECT name, number, comment, author, time " \
+              "FROM fullblog_comments WHERE " + search_clause
+        env.log.debug("search_blog_comments() SQL: %r" % sql)
+        cursor.execute(sql, args)
+        # Return the items we have found
+        return [(row[0], row[1], row[2], row[3], to_datetime(row[4], utc))
+                for row in cursor]
 
 def get_blog_posts(env, category='', author='', from_dt=None, to_dt=None,
         all_versions=False):
@@ -93,52 +93,53 @@
         (name, version, time, author, title, body, category_list)
     Use 'name' and 'version' to instantiate BlogPost objects."""
 
-    cnx = env.get_db_cnx()
-    cursor = cnx.cursor()
+    with env.db_query as cnx:
+        cursor = cnx.cursor()
 
-    # Build the list of WHERE restrictions
-    time_field = 'bp1.publish_time'
-    join_operation = ",(SELECT name, max(version) AS ver " \
-                     "FROM fullblog_posts GROUP BY name) bp2 " \
-                     "WHERE bp1.version = bp2.ver AND bp1.name = bp2.name "
-    where_clause = ""
-    where_values = None
-    if all_versions:
-        time_field = 'bp1.version_time'
-        join_operation = ""
-    args = [category and ("bp1.categories "+cnx.like(), "%"+category+"%"),
-            author and ("bp1.author=%s", author) or None,
-            from_dt and (time_field+">%s", to_timestamp(from_dt)) or None,
-            to_dt and (time_field+"<%s", to_timestamp(to_dt)) or None]
-    args = [arg for arg in args if arg]  # Ignore the None values
-    if args:
-        where_start = "AND "
-        if not join_operation:
-            where_start = "WHERE "
-        where_clause = where_start + " AND ".join([arg[0] for arg in args])
-        where_values = tuple([arg[1] for arg in args])
+        # Build the list of WHERE restrictions
+        time_field = 'bp1.publish_time'
+        join_operation = ",(SELECT name, max(version) AS ver " \
+                         "FROM fullblog_posts GROUP BY name) bp2 " \
+                         "WHERE bp1.version = bp2.ver AND bp1.name = bp2.name "
+        where_clause = ""
+        where_values = None
+        if all_versions:
+            time_field = 'bp1.version_time'
+            join_operation = ""
+        args = [category and ("bp1.categories "+cnx.like(), "%"+category+"%"),
+                author and ("bp1.author=%s", author) or None,
+                from_dt and (time_field+">%s", to_timestamp(from_dt)) or None,
+                to_dt and (time_field+"<%s", to_timestamp(to_dt)) or None]
+        args = [arg for arg in args if arg]  # Ignore the None values
+        if args:
+            where_start = "AND "
+            if not join_operation:
+                where_start = "WHERE "
+            where_clause = where_start + " AND ".join([arg[0] for arg in args])
+            where_values = tuple([arg[1] for arg in args])
 
-    # Run the SQL
-    sql = "SELECT bp1.name, bp1.version, bp1.publish_time, bp1.author, " \
-               "bp1.title, bp1.body, bp1.categories " \
-               "FROM fullblog_posts bp1 " \
-               + join_operation + where_clause \
-               + " ORDER BY bp1.publish_time DESC"
-    env.log.debug("get_blog_posts() SQL: %r (%r)" % (sql, where_values))
-    cursor.execute(sql, where_values)
+        # Run the SQL
+        sql = "SELECT bp1.name, bp1.version, bp1.publish_time, bp1.author, " \
+                   "bp1.title, bp1.body, bp1.categories " \
+                   "FROM fullblog_posts bp1 " \
+                   + join_operation + where_clause \
+                   + " ORDER BY bp1.publish_time DESC"
+        env.log.debug("get_blog_posts() SQL: %r (%r)" % (sql, where_values))
 
-    # Return the rows
-    blog_posts = []
-    for row in cursor:
-        # Extra check needed to weed out almost-matches where requested
-        # category is a substring of another (searched using LIKE)
-        categories = _parse_categories(row[6])
-        if category and category not in categories:
-            continue
-        blog_posts.append((row[0], row[1], to_datetime(row[2], utc), row[3],
-                row[4], row[5], categories))
-    return blog_posts
+        cursor.execute(sql, where_values)
 
+        # Return the rows
+        blog_posts = []
+        for row in cursor:
+            # Extra check needed to weed out almost-matches where requested
+            # category is a substring of another (searched using LIKE)
+            categories = _parse_categories(row[6])
+            if category and category not in categories:
+                continue
+            blog_posts.append((row[0], row[1], to_datetime(row[2], utc), row[3],
+                    row[4], row[5], categories))
+        return blog_posts
+
 def get_blog_comments(env, post_name='', from_dt=None, to_dt=None):
     """ Returns comments as a list of tuples from search based on
     AND input for post_name, and datetime span (from_dt and to_dt):
@@ -161,29 +162,29 @@
         where_values = tuple([arg[1] for arg in args])
 
     # Do the SELECT
-    cnx = env.get_db_cnx()
-    cursor = cnx.cursor()
-    sql = "SELECT name, number, comment, author, time " \
-            "FROM fullblog_comments " + where_clause
-    env.log.debug("get_blog_comments() SQL: %r (%r)" % (sql, where_values))
-    cursor.execute(sql, where_values or None)
+    with env.db_query as cnx:
+        cursor = cnx.cursor()
+        sql = "SELECT name, number, comment, author, time " \
+                "FROM fullblog_comments " + where_clause
+        env.log.debug("get_blog_comments() SQL: %r (%r)" % (sql, where_values))
+        cursor.execute(sql, where_values or None)
 
-    # Return the items we have found
-    return [(row[0], row[1], row[2], row[3], to_datetime(row[4], utc))
-            for row in cursor]
+        # Return the items we have found
+        return [(row[0], row[1], row[2], row[3], to_datetime(row[4], utc))
+                for row in cursor]
 
 def get_blog_resources(env):
     """ Returns a list of resource instances of existing blog posts (current
     version). The list is ordered by publish_time (newest first). """
-    cnx = env.get_db_cnx()
-    cursor = cnx.cursor()
     sql = "SELECT bp1.name FROM fullblog_posts bp1, " \
           "(SELECT name, max(version) AS ver FROM fullblog_posts " \
           "GROUP BY name) bp2 WHERE bp1.name = bp2.name AND " \
           "bp1.version = ver ORDER BY bp1.publish_time DESC"
-    cursor.execute(sql)
     blog_realm = Resource('blog')
-    return [blog_realm(id=post[0], version=0) for post in cursor]
+    with env.db_query as cnx:
+        cursor = cnx.cursor()
+        cursor.execute(sql)
+        return [blog_realm(id=post[0], version=0) for post in cursor]
 
 # Utility functions
 
@@ -279,14 +280,13 @@
         if warnings or verify_only:
             return warnings
         # No problems (we think), try to save.
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        self.env.log.debug("Creating blog comment number %d for %r" % (
-                number, self.post_name))
-        cursor.execute("INSERT INTO fullblog_comments "
-                "VALUES (%s, %s, %s, %s, %s)", (self.post_name,
-                number, comment, author, to_timestamp(self.time)) )
-        cnx.commit()
+        with self.env.db_transaction as cnx:
+            cursor = cnx.cursor()
+            self.env.log.debug("Creating blog comment number %d for %r" % (
+                    number, self.post_name))
+            cursor.execute("INSERT INTO fullblog_comments "
+                    "VALUES (%s, %s, %s, %s, %s)", (self.post_name,
+                    number, comment, author, to_timestamp(self.time)) )
         self._load_comment(number)
         return warnings
     
@@ -293,14 +293,13 @@
     def delete(self):
         if not self.post_name or not self.number:
             return False
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        self.env.log.debug("Deleting blog comment number %d for %r" % (
-                self.number, self.post_name))
-        cursor.execute("DELETE FROM fullblog_comments "
-                "WHERE name=%s AND number=%s",  (
-                self.post_name, self.number))
-        cnx.commit()
+        with self.env.db_transaction as cnx:
+            cursor = cnx.cursor()
+            self.env.log.debug("Deleting blog comment number %d for %r" % (
+                    self.number, self.post_name))
+            cursor.execute("DELETE FROM fullblog_comments "
+                    "WHERE name=%s AND number=%s",  (
+                    self.post_name, self.number))
         return True
 
     # Internal methods
@@ -307,30 +306,30 @@
     
     def _load_comment(self, number):
         """ Loads a comment from database if found. """
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        self.env.log.debug("Fetching blog comment number %d for %r" % (
-                number, self.post_name))
-        cursor.execute("SELECT comment, author, time "
-                "FROM fullblog_comments "
-                "WHERE name=%s AND number=%s",
-                (self.post_name, number))
-        for row in cursor:
-            self.number = number
-            self.comment = row[0]
-            self.author = row[1]
-            self.time = to_datetime(row[2], utc)
-            return True
+        with self.env.db_query as cnx:
+            cursor = cnx.cursor()
+            self.env.log.debug("Fetching blog comment number %d for %r" % (
+                    number, self.post_name))
+            cursor.execute("SELECT comment, author, time "
+                    "FROM fullblog_comments "
+                    "WHERE name=%s AND number=%s",
+                    (self.post_name, number))
+            for row in cursor:
+                self.number = number
+                self.comment = row[0]
+                self.author = row[1]
+                self.time = to_datetime(row[2], utc)
+                return True
         return False
     
     def _next_comment_number(self):
         """ Function that returns the next available comment number.
         If no blog post exists (can't attach comment), it returns 0. """
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        cursor.execute("SELECT number FROM fullblog_comments "
-            "WHERE name=%s", (self.post_name,))
-        cmts = sorted([row[0] for row in cursor])
+        with self.env.db_query as cnx:
+            cursor = cnx.cursor()
+            cursor.execute("SELECT number FROM fullblog_comments "
+                "WHERE name=%s", (self.post_name,))
+            cmts = sorted([row[0] for row in cursor])
         if cmts:
             return cmts[-1] + 1 # Add 1 for next free
         # No item found - need to double-check to find out why
@@ -396,16 +395,15 @@
             version = self.versions[-1] + 1
         self.env.log.debug("Saving new version %d of blog post %r "
                 "from author %r" % (version, self.name, version_author))
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        cursor.execute("INSERT INTO fullblog_posts "
-                "(name, version, title, body, publish_time, version_time, "
-                "version_comment, version_author, author, categories) "
-                "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
-                (self.name, version, self.title, self.body,
-                to_timestamp(self.publish_time), version_time,
-                version_comment, version_author, self.author, self.categories))
-        cnx.commit()
+        with self.env.db_transaction as cnx:
+            cursor = cnx.cursor()
+            cursor.execute("INSERT INTO fullblog_posts "
+                    "(name, version, title, body, publish_time, version_time, "
+                    "version_comment, version_author, author, categories) "
+                    "VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
+                    (self.name, version, self.title, self.body,
+                    to_timestamp(self.publish_time), version_time,
+                    version_comment, version_author, self.author, self.categories))
         self._load_post(version)
         return warnings
     
@@ -432,33 +430,31 @@
         """ Deletes a specific version, or if none is provided
         then all versions will be deleted. If all (or just one version exists) it
         will also delete all comments and any attachments attached to the post. """
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        if version:
-            cursor.execute("DELETE FROM fullblog_posts "
-                    "WHERE name=%s AND version=%s",
-                    (self.name, version))
-        else:
-            cursor.execute("DELETE FROM fullblog_posts "
-                    "WHERE name=%s", (self.name,))
-        cnx.commit()
+        with self.env.db_transaction as cnx:
+            cursor = cnx.cursor()
+            if version:
+                cursor.execute("DELETE FROM fullblog_posts "
+                        "WHERE name=%s AND version=%s",
+                        (self.name, version))
+            else:
+                cursor.execute("DELETE FROM fullblog_posts "
+                        "WHERE name=%s", (self.name,))
         if not len(self.get_versions()):
             # Delete comments
             for comment in self.get_comments():
                 comment.delete()
             # Delete attachments
-            Attachment.delete_all(self.env, 'blog', self.name, cnx)
-            cnx.commit()
+            Attachment.delete_all(self.env, 'blog', self.name)
         return True
     
     def get_versions(self):
         """ Returns a sorted list of versions stored for the blog post.
         Returns empty list ([]) if no versions exists. """
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        cursor.execute("SELECT version from fullblog_posts "
-                "WHERE name=%s", (self.name,) )
-        self.versions = sorted([row[0] for row in cursor])
+        with self.env.db_query as cnx:
+            cursor = cnx.cursor()
+            cursor.execute("SELECT version from fullblog_posts "
+                    "WHERE name=%s", (self.name,) )
+            self.versions = sorted([row[0] for row in cursor])
         return self.versions
         
     def get_comments(self):
@@ -482,26 +478,26 @@
             # No blog post with the name exists
             return {}
         version = version or self.versions[-1]
-        cnx = self.env.get_db_cnx()
-        cursor = cnx.cursor()
-        cursor.execute("SELECT title, body, publish_time, version_time, "
-                "version_comment, version_author, author, categories "
-                "FROM fullblog_posts "
-                "WHERE name=%s AND version=%s",
-                (self.name, version) )
-        fields = {}
-        for row in cursor:
-            fields['version'] = version
-            fields['title'] = row[0]
-            fields['body'] = row[1]
-            fields['publish_time'] = to_datetime(row[2], utc)
-            fields['version_time'] = to_datetime(row[3], utc)
-            fields['version_comment'] = row[4]
-            fields['version_author'] = row[5]
-            fields['author'] = row[6]
-            fields['categories'] = row[7]
-            fields['category_list'] = set(_parse_categories(row[7]))
-        return fields
+        with self.env.db_query as cnx:
+            cursor = cnx.cursor()
+            cursor.execute("SELECT title, body, publish_time, version_time, "
+                    "version_comment, version_author, author, categories "
+                    "FROM fullblog_posts "
+                    "WHERE name=%s AND version=%s",
+                    (self.name, version) )
+            fields = {}
+            for row in cursor:
+                fields['version'] = version
+                fields['title'] = row[0]
+                fields['body'] = row[1]
+                fields['publish_time'] = to_datetime(row[2], utc)
+                fields['version_time'] = to_datetime(row[3], utc)
+                fields['version_comment'] = row[4]
+                fields['version_author'] = row[5]
+                fields['author'] = row[6]
+                fields['categories'] = row[7]
+                fields['category_list'] = set(_parse_categories(row[7]))
+            return fields
 
     def _load_post(self, version=0):
         """ Loads the record from the database into the object.
Index: tracfullblog/tags.py
===================================================================
--- tracfullblog/tags.py	(revision 14870)
+++ tracfullblog/tags.py	(working copy)
@@ -27,9 +27,6 @@
         if 'TAGS_VIEW' not in req.perm or 'BLOG_VIEW' not in req.perm:
             return
 
-        db = self.env.get_db_cnx()
-        cursor = db.cursor()
-
         args = []
         constraints = []
         sql = "SELECT bp1.name, bp1.categories, bp1.version " \
@@ -47,14 +44,16 @@
             sql += " AND " + " AND ".join(constraints)
         sql += " ORDER BY bp1.name"
         self.env.log.debug(sql)
-        cursor.execute(sql, args)
-        for row in cursor:
-            post_name, categories = row[0], set(_parse_categories(row[1]))
-            if not tags or categories.intersection(tags):
-                resource = Resource('blog', post_name)
-                if 'BLOG_VIEW' in req.perm(resource) and \
-                        'TAGS_VIEW' in req.perm(resource):
-                    yield (resource, categories)
+        with self.env.db_query as db:
+            cursor = db.cursor()
+            cursor.execute(sql, args)
+            for row in cursor:
+                post_name, categories = row[0], set(_parse_categories(row[1]))
+                if not tags or categories.intersection(tags):
+                    resource = Resource('blog', post_name)
+                    if 'BLOG_VIEW' in req.perm(resource) and \
+                            'TAGS_VIEW' in req.perm(resource):
+                        yield (resource, categories)
 
     def get_resource_tags(self, req, resource):
         req.perm(resource).require('BLOG_VIEW')
Index: tracfullblog/templates/fullblog.rss
===================================================================
--- tracfullblog/templates/fullblog.rss	(revision 14870)
+++ tracfullblog/templates/fullblog.rss	(working copy)
@@ -2,7 +2,6 @@
 <rss version="2.0" xmlns:py="http://genshi.edgewall.org/"
                    xmlns:dc="http://purl.org/dc/elements/1.1/"
                    xmlns:xi="http://www.w3.org/2001/XInclude">
-  <xi:include href="macros.rss" />
   <channel>
     <title>${project.name} - Blog</title>
     <link>${abs_href.blog()}</link>
Index: tracfullblog/templates/fullblog_archive.html
===================================================================
--- tracfullblog/templates/fullblog_archive.html	(revision 14870)
+++ tracfullblog/templates/fullblog_archive.html	(working copy)
@@ -5,7 +5,6 @@
       xmlns:py="http://genshi.edgewall.org/"
       xmlns:xi="http://www.w3.org/2001/XInclude">
   <xi:include href="layout.html" />
-  <xi:include href="macros.html" />
   <head>
     <title>Blog Archive</title>
     <meta name="ROBOTS" content="NOINDEX" />
Index: tracfullblog/templates/fullblog_delete.html
===================================================================
--- tracfullblog/templates/fullblog_delete.html	(revision 14870)
+++ tracfullblog/templates/fullblog_delete.html	(working copy)
@@ -5,7 +5,6 @@
       xmlns:py="http://genshi.edgewall.org/"
       xmlns:xi="http://www.w3.org/2001/XInclude">
   <xi:include href="layout.html" />
-  <xi:include href="macros.html" />
   <head>
     <title>Blog : Delete</title>
   </head>
Index: tracfullblog/templates/fullblog_edit.html
===================================================================
--- tracfullblog/templates/fullblog_edit.html	(revision 14870)
+++ tracfullblog/templates/fullblog_edit.html	(working copy)
@@ -5,7 +5,6 @@
       xmlns:py="http://genshi.edgewall.org/"
       xmlns:xi="http://www.w3.org/2001/XInclude">
   <xi:include href="layout.html" />
-  <xi:include href="macros.html" />
   <head>
     <title>Edit Blog Post</title>
   </head>
Index: tracfullblog/templates/fullblog_post.rss
===================================================================
--- tracfullblog/templates/fullblog_post.rss	(revision 14870)
+++ tracfullblog/templates/fullblog_post.rss	(working copy)
@@ -2,7 +2,6 @@
 <rss version="2.0" xmlns:py="http://genshi.edgewall.org/"
                    xmlns:dc="http://purl.org/dc/elements/1.1/"
                    xmlns:xi="http://www.w3.org/2001/XInclude">
-  <xi:include href="macros.rss" />
   <channel py:with="bp = blog_post">
     <title>${project.name} - Blog: ${bp.title}</title>
     <link>${abs_href.blog(bp.name)}</link>
Index: tracfullblog/templates/fullblog_view.html
===================================================================
--- tracfullblog/templates/fullblog_view.html	(revision 14870)
+++ tracfullblog/templates/fullblog_view.html	(working copy)
@@ -5,7 +5,6 @@
       xmlns:py="http://genshi.edgewall.org/"
       xmlns:xi="http://www.w3.org/2001/XInclude">
   <xi:include href="layout.html" />
-  <xi:include href="macros.html" />
   <head>
     <title>Blog${defined('blog_post') and ': ' + blog_post.title \
                 or req.args.get('blog_path') and defined('blog_list_title') \
@@ -45,7 +44,8 @@
                   <input type="submit" value="${_('Edit post')}" accesskey="e" />
                 </div>
               </form>
-              ${attach_file_form(blog_attachments)}
+              <xi:include href="attach_file_form.html"
+                          py:with="alist = blog_attachments"/>
               <form method="get" action="${href.blog('delete', blog_post.name)}"
                     py:if="'BLOG_DELETE' in perm(blog_post.resource)">
                 <div>
@@ -57,7 +57,8 @@
           </py:if>
         
           <!--! List attachments -->
-          ${list_of_attachments(blog_attachments, compact=True)}
+          <xi:include href="list_of_attachments.html"
+                      py:with="alist = blog_attachments; compact = True"/>
 
           <!--! View comments -->
           <div id="comments" py:with="blog_comments = blog_post.get_comments()">
