django-markdownx is a Markdown editor built for Django
Find a file
2017-03-10 11:08:57 +01:00
markdownx Small refactoring: events naming, logging only errors in console. 2017-03-10 10:47:49 +01:00
testapp testapp update 2017-01-16 21:10:09 +01:00
.gitignore Setuptools related 2014-11-03 10:00:53 +01:00
.travis.yml Python 3.6 support 2017-01-16 20:39:31 +00:00
django-markdownx-preview.gif Works for 1.0 version 2015-09-06 20:46:46 +02:00
LICENSE Licence fix 2016-05-14 21:31:11 +02:00
MANIFEST.in v1.1.3 2015-10-09 10:44:28 +02:00
README.md Small refactoring: events naming, logging only errors in console. 2017-03-10 10:47:49 +01:00
requirements.txt v1.1.0 2015-09-30 13:22:35 +02:00
runtests.py Runtest template fix 2016-08-15 14:01:09 +02:00
setup.cfg Universal wheel 2016-06-18 11:10:12 +02:00
setup.py setup.py update 2017-03-10 11:08:57 +01:00

django-markdownx Version

Status Travis Format Python Versions Django Versions License

Key features

  • raw editing
  • live preview
  • drag&drop image uploads (stored locally in MEDIA folder)
  • customizable image insertion tag
  • image filtering using content types and max file size
  • image manipulations (compression, size, cropping, upscaling)
  • pre-&post- text altering
  • easy template customization for layout purposes
  • multiple editors on one page
  • Django Admin support

Preview

Preview

(using Bootstrap for layout and styling)

Menu

Quick Start

  1. Install django-markdownx package.

    pip install django-markdownx
    
  2. Add markdownx to your INSTALLED_APPS.

    #settings.py
    INSTALLED_APPS = (
        [...]
        'markdownx',
    )
    
  3. Add url pattern to your urls.py.

    #urls.py
    urlpatterns = [
        [...]
        url(r'^markdownx/', include('markdownx.urls')),
    ]
    
  4. Collect included markdownx.js and markdownx.css (for django admin styling) to your STATIC_ROOT folder.

    python manage.py collectstatic
    
  5. ...and don't forget to include jQuery in your html file.

    <head>
        [...]
        <script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
    </head>
    

Usage

Model

#models.py
from markdownx.models import MarkdownxField

class MyModel(models.Model):

    myfield = MarkdownxField()

...and then, include a form's required media in the template using {{ form.media }}:

<form method="POST" action="">{% csrf_token %}
    {{ form }}
</form>
{{ form.media }}

Form

#forms.py
from markdownx.fields import MarkdownxFormField

class MyForm(forms.Form):

    myfield = MarkdownxFormField()

...and then, include a form's required media in the template using {{ form.media }}:

<form method="POST" action="">{% csrf_token %}
    {{ form }}
</form>
{{ form.media }}

Django Admin

When using included MarkdowxModel class in your models, just use MarkdownxModelAdmin as follows:

#admin.py
from django.contrib import admin

from markdownx.admin import MarkdownxModelAdmin

from .models import MyModel

admin.site.register(MyModel, MarkdownxModelAdmin)

However, when you want to use markdownx with other classes lets say TextField than override default widget as follows:

#admin.py
from django.db import models
from django.contrib import admin

from markdownx.widgets import AdminMarkdownxWidget

from .models import MyModel

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.TextField: {'widget': AdminMarkdownxWidget},
    }

admin.site.register(MyModel, MyModelAdmin)

Customization

Settings

Place settings in your settings.py to override default values:

#settings.py

# Markdownify
MARKDOWNX_MARKDOWNIFY_FUNCTION = 'markdownx.utils.markdownify' # Default function that compiles markdown using defined extensions. Using custom function can allow you to pre-process or post-process markdown text. See below for more info.

# Markdown extensions
MARKDOWNX_MARKDOWN_EXTENSIONS = [] # List of used markdown extensions. See below for more info.
MARKDOWNX_MARKDOWN_EXTENSION_CONFIGS = {} # Configuration object for used markdown extensions

# Markdown urls
MARKDOWNX_URLS_PATH = '/markdownx/markdownify/' # URL that returns compiled markdown text.
MARKDOWNX_UPLOAD_URLS_PATH = '/markdownx/upload/' # URL that accepts file uploads, returns markdown notation of the image.

# Media path
MARKDOWNX_MEDIA_PATH = 'markdownx/' # Path, where images will be stored in MEDIA_ROOT folder

# Image
MARKDOWNX_UPLOAD_MAX_SIZE = 52428800 # 50MB - maximum file size
MARKDOWNX_UPLOAD_CONTENT_TYPES = ['image/jpeg', 'image/png', 'image/svg+xml'] # Acceptable file content types
MARKDOWNX_IMAGE_MAX_SIZE = {'size': (500, 500), 'quality': 90,} # Different options describing final image processing: size, compression etc. See below for more info. Dimensions are not applied to SVG files.

# Editor
MARKDOWNX_EDITOR_RESIZABLE = True # Update editor's height to inner content height while typing

MARKDOWNX_MARKDOWNIFY_FUNCTION

Default function that compiles markdown looks like:

# utils.py
import markdown

from .settings import MARKDOWNX_MARKDOWN_EXTENSIONS, MARKDOWNX_MARKDOWN_EXTENSION_CONFIGS

def markdownify(content):
    return markdown.markdown(content, extensions=MARKDOWNX_MARKDOWN_EXTENSIONS, extension_configs=MARKDOWNX_MARKDOWN_EXTENSION_CONFIGS)

MARKDOWNX_MARKDOWN_EXTENSIONS

#settings.py
MARKDOWNX_MARKDOWN_EXTENSIONS = [
    'markdown.extensions.extra',
    'markdown.extensions.nl2br',
    'markdown.extensions.smarty',
]

Visit https://pythonhosted.org/Markdown/extensions/index.html to read more about markdown extensions.

MARKDOWNX_IMAGE_MAX_SIZE

Dict properties:

  • size (width, height). When 0 used, i.e.: (500,0), property will figure out proper height by itself
  • quality default: 90 image quality, from 0 (full compression) to 100 (no compression)
  • crop default: False if True, use size to crop final image
  • upscale default: False if image dimensions are smaller than those in size, upscale image to size dimensions

Widget's custom template

Default widget's template looks like:

<div class="markdownx">
    {{ markdownx_editor }}
    <div class="markdownx-preview"></div>
</div>

When you want to use Bootstrap 3 and side-by-side panes (as in preview image above), just place markdownx/widget.html file in your project's 'TEMPLATE_DIRS' folder with:

<div class="markdownx row">
    <div class="col-md-6">
        {{ markdownx_editor }}
    </div>
    <div class="col-md-6">
        <div class="markdownx-preview"></div>
    </div>
</div>

Custom image insertion tag

Markdown uses ![]() syntax to insert uploaded image file. This generates very simple html <image> tag. When you want to have more control and use your own html tags just create custom form_valid() function in ImageUploadView class.

Default ImageUploadView class looks like:

#views.py
from django.http import JsonResponse
from django.views.generic.edit import FormView

from .forms import ImageForm

class ImageUploadView(FormView):

    template_name = "dummy.html"
    form_class = ImageForm
    success_url = '/'

    def form_invalid(self, form):
        response = super(ImageUploadView, self).form_invalid(form)
        if self.request.is_ajax():
            return JsonResponse(form.errors, status=400)
        else:
            return response

    def form_valid(self, form):
        image_path = form.save()
        response = super(ImageUploadView, self).form_valid(form)

        if self.request.is_ajax():
            image_code = '![]({})'.format(image_path)
            return JsonResponse({'image_code': image_code})
        else:
            return response

JS events

Each markdownx jQuery object triggers these basic events:

  • markdownx.init is triggered after jQuery plugin init
  • markdownx.update is triggered when editor text is markdownified. Returns response variable containing markdownified text.
  • markdownx.update_error is triggered when a problem occured during markdownify.
  • markdownx.file_upload_begin is triggered when the file is posted.
  • markdownx.file_upload_end is triggered when the file has been uploaded.
  • markdownx.file_upload_error is triggered if the upload didn't work.

To handle events in JS use:

$('.markdownx').on('markdownx.init', function() {
    console.log("init");
});

$('.markdownx').on('markdownx.update', function(e, response) {
    console.log("update " + response);
});

$('.markdownx').on('markdownx.update_error', function(e) {
    console.log("update error");
});

$('.markdownx').on('markdownx.file_upload_begin', function(e) {
    console.log("Uploading has started.");
});

$('.markdownx').on('markdownx.file_upload_end', function(e) {
    console.log("Uploading has ended.");
});

$('.markdownx').on('markdownx.file_upload_error', function(e) {
    console.log("Error during file upload");
});

Dependencies

  • Markdown
  • Pillow
  • Django
  • jQuery

License

django-markdown is licensed under the open source BSD license. Read LICENSE file for details.

Package requests

It would be nice if anyone could support this project by adding missing functionality:

  • tests
  • JS intelligent auto-scrolling when side-by-side panes used

Notes

django-markdownx was inspired by great django-images and django-bootstrap-markdown packages.