Ticket #10317: markupfield-with-docs.diff

File markupfield-with-docs.diff, 9.3 KB (added by James Turk, 10 years ago)

markupfield implementation and markup docs changes (now with extra options)

  • new file django/contrib/markup/fields.py

    diff --git a/django/contrib/markup/fields.py b/django/contrib/markup/fields.py
    new file mode 100644
    index 0000000..230e388
    - +  
     1from django.db import models
     2from django.utils.html import linebreaks, urlize
     3from django.utils.safestring import mark_safe
     4
     5PLAIN_TEXT, HTML, MARKDOWN, REST, TEXTILE = range(5)
     6
     7# determine available choices dynamically upon first import
     8MARKUP_TYPES = (
     9    (PLAIN_TEXT, 'plain'),
     10    (HTML, 'html'),
     11)
     12
     13try:
     14    import markdown
     15    MARKUP_TYPES += ( (MARKDOWN, 'markdown'), )
     16except ImportError:
     17    pass
     18
     19try:
     20    from docutils.core import publish_parts
     21    MARKUP_TYPES += ( (REST, 'restructuredtext'), )
     22except ImportError:
     23    pass
     24
     25try:
     26    import textile
     27    MARKUP_TYPES += ( (TEXTILE, 'textile'), )
     28except ImportError:
     29    pass
     30
     31_rendered_field_name = lambda name: '%s_rendered' % name
     32_markup_type_field_name = lambda name: '%s_markup_type' % name
     33
     34class MarkupField(models.TextField):
     35    def __init__(self, verbose_name=None, name=None,
     36                 default_markup_type=PLAIN_TEXT, sanitize=False,
     37                 extra_options=None, **kwargs):
     38        self.default_markup_type = default_markup_type
     39        self.extra_options = extra_options
     40        self.sanitize = sanitize
     41        super(MarkupField, self).__init__(verbose_name, name, **kwargs)
     42
     43    def contribute_to_class(self, cls, name):
     44        # add markup_type field with creation_counter 1 greater than self
     45        # so that admin by default shows these fields together
     46        markup_type_field = models.PositiveIntegerField(choices=MARKUP_TYPES,
     47                                                        default=self.default_markup_type,
     48                                                        blank=self.blank)
     49        markup_type_field.creation_counter = self.creation_counter+1
     50        cls.add_to_class(_markup_type_field_name(name), markup_type_field)
     51        rendered_field = models.TextField(editable=False)
     52        cls.add_to_class(_rendered_field_name(name), rendered_field)
     53        super(MarkupField, self).contribute_to_class(cls, name)
     54
     55        # define read-only property to easily access rendered string
     56        def as_html(self):
     57            return mark_safe(getattr(self, _rendered_field_name(name)))
     58        cls.add_to_class('%s_as_html' % name, property(as_html))
     59
     60    def pre_save(self, instance, add):
     61        # update rendered value on save
     62        markup = getattr(instance, self.attname)
     63        markup_type = getattr(instance, _markup_type_field_name(self.attname))
     64        rendered = self.render_markup(markup, markup_type)
     65        setattr(instance, _rendered_field_name(self.attname), rendered)
     66
     67        return markup
     68
     69    def render_markup(self, markup, markup_type):
     70        """
     71        Renders ``markup`` string to HTML calling the renderer specified by
     72        ``markup_type``.
     73        """
     74        if markup_type == MARKDOWN:
     75            # markdown.version implies support for extensions
     76            if hasattr(markdown, 'version'):
     77                return markdown.markdown(markup, self.extra_options,
     78                                         safe_mode=self.sanitize)
     79            return markdown.markdown(markup)
     80        elif markup_type == REST:
     81            # use extra_options as settings_overrides
     82            parts = publish_parts(source=markup, writer_name="html4css1",
     83                                  settings_overrides=self.extra_options)
     84            return parts["fragment"]
     85        elif markup_type == TEXTILE:
     86            return textile.textile(markup, encoding='utf-8', output='utf-8',
     87                                   sanitize=self.sanitize)
     88        elif markup_type == PLAIN_TEXT:
     89            return urlize(linebreaks(markup))
     90        else:
     91            return markup
  • docs/ref/contrib/index.txt

    diff --git a/docs/ref/contrib/index.txt b/docs/ref/contrib/index.txt
    index 82a8955..16d0c32 100644
    a b those packages have. 
    3434   formtools/index
    3535   humanize
    3636   localflavor
     37   markup
    3738   redirects
    3839   sitemaps
    3940   sites
    contains a ``USZipCodeField`` that you can use to validate U.S. zip codes. 
    126127
    127128See the :ref:`localflavor documentation <ref-contrib-localflavor>`.
    128129
    129 .. _ref-contrib-markup:
    130 
    131130markup
    132131======
    133132
    134 A collection of template filters that implement common markup languages:
    135 
    136     * ``textile`` -- implements `Textile`_
    137     * ``markdown`` -- implements `Markdown`_
    138     * ``restructuredtext`` -- implements `ReST (ReStructured Text)`_
    139 
    140 In each case, the filter expects formatted markup as a string and returns a
    141 string representing the marked-up text. For example, the ``textile`` filter
    142 converts text that is marked-up in Textile format to HTML.
    143 
    144 To activate these filters, add ``'django.contrib.markup'`` to your
    145 :setting:`INSTALLED_APPS` setting. Once you've done that, use ``{% load markup %}`` in
    146 a template, and you'll have access to these filters. For more documentation,
    147 read the source code in django/contrib/markup/templatetags/markup.py.
     133Utilities for using common markup languages.
    148134
    149 .. _Textile: http://en.wikipedia.org/wiki/Textile_%28markup_language%29
    150 .. _Markdown: http://en.wikipedia.org/wiki/Markdown
    151 .. _ReST (ReStructured Text): http://en.wikipedia.org/wiki/ReStructuredText
     135See the :ref:`markup documentation <ref-contrib-markup>`.
    152136
    153137redirects
    154138=========
  • new file docs/ref/contrib/markup.txt

    diff --git a/docs/ref/contrib/markup.txt b/docs/ref/contrib/markup.txt
    new file mode 100644
    index 0000000..c9d6119
    - +  
     1.. _ref-contrib-markup:
     2
     3======================
     4django.contrib.markup
     5======================
     6
     7.. module:: django.contrib.markup
     8   :synopsis: Utilities for using common markup languages.
     9
     10Two different methods of dealing with markup are offered: `Template Filters`_
     11for rendering any block of text and a special :class:`MarkupField` that
     12provides a convenient way to store markup alongside it's type and
     13pre-rendered HTML in the database.
     14
     15Template Filters
     16----------------
     17
     18A collection of template filters that implement common markup languages:
     19
     20    * ``textile`` -- implements `Textile`_
     21    * ``markdown`` -- implements `Markdown`_
     22    * ``restructuredtext`` -- implements `ReST (ReStructured Text)`_
     23
     24In each case, the filter expects formatted markup as a string and returns a
     25string representing the marked-up text. For example, the ``textile`` filter
     26converts text that is marked-up in Textile format to HTML.
     27
     28To activate these filters, add ``'django.contrib.markup'`` to your
     29:setting:`INSTALLED_APPS` setting. Once you've done that, use
     30``{% load markup %}`` in a template, and you'll have access to these filters.
     31For more documentation, read the source code in
     32django/contrib/markup/templatetags/markup.py.
     33
     34.. _Textile: http://en.wikipedia.org/wiki/Textile_%28markup_language%29
     35.. _Markdown: http://en.wikipedia.org/wiki/Markdown
     36.. _ReST (ReStructured Text): http://en.wikipedia.org/wiki/ReStructuredText
     37
     38
     39``MarkupField``
     40---------------
     41
     42.. class:: MarkupField([default_markup_type=PLAIN_TEXT, **options])
     43
     44A :class:`TextField` that also adds an associated field for storing a markup
     45type and a read only accessor for getting the rendered HTML. Has a few optional
     46arguments:
     47
     48.. attribute:: MarkupField.default_markup_type
     49
     50    Optional. Choice from ``MARKUP_TYPES`` to be used as the default value
     51    for the associated markup_type field.
     52
     53.. attribute: MarkupField.sanitize
     54
     55    Optional. Tell underlying renderer to strip HTML. (supported for
     56    Markdown and Textile)
     57
     58.. attribute: MarkupField.extra_options
     59
     60    Optional. Set of extra options to pass to renderer.  This parameter is
     61    passed to ``markdown.markdown`` as ``extensions`` and to
     62    ``docutils.core.publish_parts`` as ``settings_overrides``.
     63
     64This field has slightly more complicated internals than the typical field.
     65Behind the scenes it actually creates additional fields, for example::
     66
     67    from django.contrib.markup.fields import MarkupField
     68   
     69    class Post(models.Model):
     70        body = MarkupField()
     71
     72...Instances of Post would have the additional attributes ``body_markup_type``
     73and ``body_as_html``. ``body_markup_type`` is a :class:`PositiveIntegerField`
     74with choices defined in ``MARKUP_TYPES``. ``body_as_html`` is a read-only
     75property containing a pre-rendered HTML version of the content assigned to
     76``body``.
     77
     78.. versionadded:: 1.2
     79   ``MarkupField`` was added in this version.
     80
     81MARKUP_TYPES
     82------------
     83
     84Choices for markup_type field:
     85
     86======================  ======================================================
     87Type                    Description
     88======================  ======================================================
     89``PLAIN_TEXT``          Applies urlize and linebreak filters.
     90
     91``HTML``                Applies no filters, ``field_as_html`` returns the body
     92                        verbatim.
     93
     94``MARKDOWN``            `Markdown`_ (only available if markdown library is
     95                        available)
     96
     97``REST``                `ReST (ReStructured Text)`_ (only available if
     98                        docutils is installed)
     99
     100``TEXTILE``             `Textile`_ (only available if textile library is
     101                        installed)
     102======================  ======================================================
Back to Top