Commits

Ollie Rutherfurd committed d7da8a4

initial version

Comments (0)

Files changed (7)

+syntax: glob
+*~
+*.orig
+*.pyc
+*.rej
+*.swp
+tags
+
+syntax: regexp
+
+^build/
+^tmp/
+===================
+django-easymarkdown
+===================
+
+A MarkdownField for Django.  Converts `Markdown` to HTML, saving the
+generated HTML in the DB (in an automatically generated field).
+
+.. _Markdown: http://daringfireball.net/projects/markdown/
+
+The code is based on `django-markupfield`_, but intentionally
+stripped-down and uses `markdown2`_ to convert markdown to HTML.
+
+.. _django-markupfield: http://pypi.python.org/pypi/django-markupfield/
+
+Requirements
+============
+
+* `markdown2 <http://code.google.com/p/python-markdown2/>`_
+
+* markdown "extras" -- both default and on a per field basis
+* wysiwyg?

easymarkdown/__init__.py

+from fields import *
+from widgets import *

easymarkdown/fields.py

+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)
+
+# 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}
+

easymarkdown/widgets.py

+from django import forms
+from django.contrib.admin.widgets import AdminTextareaWidget
+
+__all__ = [
+    'AdminMarkdownTextareaWidget',
+    'MarkdownTextarea',
+]
+
+class MarkdownTextarea(forms.widgets.Textarea):
+    def render(self, name, value, attrs=None):
+        if value is not None and not isinstance(value, unicode):
+            value = value.markdown
+        return super(MarkdownTextarea, self).render(name, value, attrs)
+
+class AdminMarkdownTextareaWidget(MarkdownTextarea, AdminTextareaWidget):
+    pass
+from distutils.core import setup
+import os,re,sys
+
+def _stripsourcecode(s):
+    # replace sourcecode blocks with literal blocks
+    return re.sub(r'\.\. sourcecode:: \w+', '::', s.strip())
+
+VERSION='0.1'
+
+setup(
+    name='django-easymarkdown',
+    description="A MarkdownField for Django",
+    author='Ollie Rutherfurd',
+    author_email='oliver@rutherfurd.net',
+    version=VERSION,
+    license='BSD',
+    packages=['easymarkdown'],
+    classifiers=[
+        'Development Status :: 3 - Alpha',
+        'Environment :: Web Environment',
+        'Framework :: Django',
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: BSD License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+    ],
+    long_description=_stripsourcecode(open('README.rst').read()),
+    platforms=['any'],
+)