| 1 | """Proof of concept for on-the-fly, standalone DJango filter code.
|
|---|
| 2 |
|
|---|
| 3 | Problem: in some of my work I use the nifty DJango template code
|
|---|
| 4 | for documentation generation in standalone code - i.e. I generate
|
|---|
| 5 | documentation of some form without using any web app/infrastructure
|
|---|
| 6 | at all.
|
|---|
| 7 |
|
|---|
| 8 | DJango can works fine sans-web so long as you set it up correctly
|
|---|
| 9 | and you don't use custom filters or tags.
|
|---|
| 10 |
|
|---|
| 11 | Actually, thats not 100% true. You *can* use custom filters and tags,
|
|---|
| 12 | but it takes a bit of magic that I didn't think should be necessary.
|
|---|
| 13 |
|
|---|
| 14 | The challenge was to submit a patch to the DJango code, but to do
|
|---|
| 15 | that I need a small demo app that proves the new work..
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 | Objective: Render a template, completely standalone, using custom filters
|
|---|
| 19 | and tags, in a "Django-compliant" way with minimal code changes to DJango.
|
|---|
| 20 |
|
|---|
| 21 | Specifically, this demo renders some restructured text using filters
|
|---|
| 22 | to generate underlines and header formatting.
|
|---|
| 23 |
|
|---|
| 24 | Remember: the changes to DJango mustn't break any existing behavior!
|
|---|
| 25 |
|
|---|
| 26 | A. Roark, June 2007
|
|---|
| 27 | """
|
|---|
| 28 | import sys, re, os, os.path
|
|---|
| 29 |
|
|---|
| 30 | try: import django
|
|---|
| 31 | except ImportError, e:
|
|---|
| 32 | sys.stderr.write("DJango not installed\n")
|
|---|
| 33 | sys.exit(1)
|
|---|
| 34 |
|
|---|
| 35 | template_content="""{{ title|rst_format_title:"=" }}
|
|---|
| 36 |
|
|---|
| 37 | {{author|rst_format_author}}
|
|---|
| 38 | {% rst_doc_date %}
|
|---|
| 39 |
|
|---|
| 40 | {{subtitle|rst_format_h1}}
|
|---|
| 41 |
|
|---|
| 42 | {{para}}
|
|---|
| 43 | """
|
|---|
| 44 |
|
|---|
| 45 | def do_filter_demo():
|
|---|
| 46 | """Render a template from a string using our local filter.
|
|---|
| 47 |
|
|---|
| 48 | This will render something like:
|
|---|
| 49 | >>>
|
|---|
| 50 | ===============
|
|---|
| 51 | Filtered Demo
|
|---|
| 52 | ===============
|
|---|
| 53 |
|
|---|
| 54 | :Author: A. Roark
|
|---|
| 55 | :Date: 2007-06-30 21:45:40.205000
|
|---|
| 56 |
|
|---|
| 57 | Simple restructured text demo
|
|---|
| 58 | -----------------------------
|
|---|
| 59 |
|
|---|
| 60 | This uses builtin filters for formatting text
|
|---|
| 61 | <<<
|
|---|
| 62 | """
|
|---|
| 63 |
|
|---|
| 64 | # Render the template here - note that no special imports/code needed.
|
|---|
| 65 | t=Template(template_content)
|
|---|
| 66 | context=Context({
|
|---|
| 67 | 'title': 'Filtered Demo',
|
|---|
| 68 | 'author': 'A. Roark',
|
|---|
| 69 | 'subtitle': 'Simple restructured text demo',
|
|---|
| 70 | 'para': 'This uses builtin filters for formatting text',
|
|---|
| 71 | })
|
|---|
| 72 | out=t.render(context)
|
|---|
| 73 | print "\nDjango Custom Filter Demo:\n>>>\n%s\n<<<\n" % out
|
|---|
| 74 |
|
|---|
| 75 |
|
|---|
| 76 | #
|
|---|
| 77 | # --- Define some filters here ---
|
|---|
| 78 | #
|
|---|
| 79 |
|
|---|
| 80 | def filter_rst_h1(value, arg='-'):
|
|---|
| 81 | "Write a single underline under the text"
|
|---|
| 82 | line=arg * len(value)
|
|---|
| 83 | return "%s\n%s" % (value, line)
|
|---|
| 84 |
|
|---|
| 85 | def filter_rst_title(value, arg='-'):
|
|---|
| 86 | "Add a line before and after the text"
|
|---|
| 87 | line=arg * (2+len(value))
|
|---|
| 88 | return "%s\n %s \n%s" % (line, value, line)
|
|---|
| 89 |
|
|---|
| 90 | def filter_rst_author(value, arg=None):
|
|---|
| 91 | return ":Author: %s" %value
|
|---|
| 92 |
|
|---|
| 93 | #
|
|---|
| 94 | # --- A simple tag ---
|
|---|
| 95 | #
|
|---|
| 96 | def tag_rst_doc_date(parser, token):
|
|---|
| 97 | # A "real" tag should be much more than this -
|
|---|
| 98 | # I'm amazed this works as-is, but its ok for a demo.
|
|---|
| 99 | # For real details, see:
|
|---|
| 100 | # http://www.djangoproject.com/documentation/templates_python/#writing-the-compilation-function
|
|---|
| 101 | import datetime
|
|---|
| 102 | return ":Date: %s" % datetime.datetime.now()
|
|---|
| 103 |
|
|---|
| 104 | #
|
|---|
| 105 | # --- Main code ---
|
|---|
| 106 | #
|
|---|
| 107 | if __name__ == "__main__":
|
|---|
| 108 |
|
|---|
| 109 | # In a standalone app, do this first, before other imports
|
|---|
| 110 | from django.conf import settings
|
|---|
| 111 | settings.configure(
|
|---|
| 112 | # for debug:
|
|---|
| 113 | # DEBUG=True, TEMPLATE_DEBUG=True,
|
|---|
| 114 | # for template files, something like...
|
|---|
| 115 | # TEMPLATE_DIRS=(root_dir, os.path.join(root_dir, 'ref'))
|
|---|
| 116 | )
|
|---|
| 117 |
|
|---|
| 118 | from django.template import Template, Context, BuiltinLibrary
|
|---|
| 119 |
|
|---|
| 120 | # set up extra library of routines for later use...
|
|---|
| 121 | custom_library = BuiltinLibrary()
|
|---|
| 122 | custom_library.filter('rst_format_title', filter_rst_title)
|
|---|
| 123 | custom_library.filter('rst_format_h1', filter_rst_h1)
|
|---|
| 124 | custom_library.filter('rst_format_author', filter_rst_author)
|
|---|
| 125 | custom_library.tag( 'rst_doc_date', tag_rst_doc_date)
|
|---|
| 126 |
|
|---|
| 127 | do_filter_demo()
|
|---|
| 128 |
|
|---|