Code


Version 9 (modified by anonymous, 7 years ago) (diff)

--

CookBook - Using Markup Filters in Models

The markup application (django.contrib.markup) is pretty handy for using filters like Textile or Markdown in your templates, but has a slight downside: every time a page is generated, you have to run the markup filter over the text, which may or may not be an acceptable performance hit. You could, if you wanted, just define a save() hook which applies the filter to incoming text so it gets saved to your DB as HTML, but then you're in a pickle if you want to edit it again later. What to do, then?

One solution is found in the Textpattern CMS, which incorporates Textile. Textpattern accepts input in Textile syntax, and then saves two copies: one is the raw input, which is stored for later use when an item is being edited, and the other is the XHTML Textile produces for that input, which is used for actual page display. The idea here is that database columns are cheap, but processing time might not be. And this is easy to do in Django; for example, let's say you have a weblog where you'd like to use Markdown on the entries. You might define your Entry model like so:

class Entry(models.Model):
    title = .CharField('Title', maxlength=250)
    pub_date = models.DateTimeField('Date published', default=meta.LazyDate())
    body_markdown = models.TextField('Entry body', help_text='Use Markdown syntax.')
    body = models.TextField('Entry body as HTML', blank=True, null=True)

    class Admin:
        fields = (
            (None, {'fields': ('title', 'pub_date', 'body_markdown')}),
            )
        )

    def save(self):
        import markdown
        self.body = markdown.markdown(self.body_markdown)
        super(Entry, self).save() # Call the "real" save() method.

Now you've got the same effect: when creating or editing entries in the admin, you'll only see the field which accepts Markdown syntax (body_markdown), but when saving, the "body" field will be auto-filled with the corresponding XHTML. Then in your template, you can pull in entry.body, and save yourself a little processing time everytime the page is loaded.