Source

django-easymarkdown / easymarkdown / fields.py

Full commit
from django.db import models
from django.utils.safestring import mark_safe
from . import widgets
import markdown2

__all__ = [
    'MarkdownField',
]

_html_field_name = lambda name: '%s_html' % name


class Markdown(object):
    def __init__(self, instance, field_name, html_field_name):
        self.instance = instance
        self.field_name = field_name
        self.html_field_name = html_field_name
    
    def _get_markdown(self):
        return self.instance.__dict__[self.field_name]
    def _set_markdown(self, value):
        setattr(self.instance, self.field_name, value)
    markdown = property(_get_markdown, _set_markdown)
    
    @property
    def html(self):
        return getattr(self.instance, self.html_field_name)
    
    def __unicode__(self):
        return mark_safe(self.html)


class MarkdownDescriptor(property):
    
    def __init__(self, field):
        self.field = field
        self.html_field_name = _html_field_name(self.field.name)
    
    def __get__(self, instance, owner):
        if instance is None:
            raise AttributeError('Can only be accessed via an instance.')
        markdown = instance.__dict__[self.field.name]
        if markdown is None:
            return None
        return Markdown(instance, self.field.name, self.html_field_name)
    
    def __set__(self, obj, value):
        if isinstance(value, Markdown):
            obj.__dict__[self.field.name] = value.markdown
            setattr(obj, self.html_field_name, value.html)
        else:
            obj.__dict__[self.field.name] = value


class MarkdownField(models.TextField):
    
    def contribute_to_class(self, cls, name):
        html_field = models.TextField(editable=False)
        html_field.creation_counter = self.creation_counter+1
        cls.add_to_class(_html_field_name(name), html_field)
        super(MarkdownField, self).contribute_to_class(cls, name)
        setattr(cls, self.name, MarkdownDescriptor(self))
    
    def pre_save(self, model_instance, add):
        value = super(MarkdownField, self).pre_save(model_instance, add)
        html = markdown2.markdown(value.markdown)
        setattr(model_instance, _html_field_name(self.attname), html)
        return value.markdown
    
    def get_db_prep_value(self, value):
        if isinstance(value, Markdown):
            return value.markdown
        return value
    
    def value_to_string(self, obj):
        value = self._get_val_from_obj(obj)
        return value.markdown
    
    def formfield(self, **kw):
        defaults = {'widget': widgets.MarkdownTextarea}
        defaults.update(kw)
        return super(MarkdownField, self).formfield(**defaults)

    def south_field_triple(self):
        "Returns a suitable description of this field for South."
        try:
            from south.modelsinspector import introspector
        except ImportError:
            introspector = lambda self: [], {}
        args, kwargs = introspector(self)
        return ('easymarkdown.MarkdownField', args, kwargs)


# use custom widget by default in the admin
from django.contrib.admin.options import FORMFIELD_FOR_DBFIELD_DEFAULTS
FORMFIELD_FOR_DBFIELD_DEFAULTS[MarkdownField] = {'widget': widgets.AdminMarkdownTextareaWidget}