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
(using Bootstrap for layout and styling)
Menu
Quick Start
-
Install
django-markdownx
package.pip install django-markdownx
-
Add
markdownx
to yourINSTALLED_APPS
.#settings.py INSTALLED_APPS = ( [...] 'markdownx', )
-
Add url pattern to your
urls.py
.#urls.py urlpatterns = [ [...] url(r'^markdownx/', include('markdownx.urls')), ]
-
Collect included
markdownx.js
andmarkdownx.css
(for django admin styling) to yourSTATIC_ROOT
folder.python manage.py collectstatic
-
...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'] # 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.
# 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, from0
(full compression) to100
(no compression) -
crop – default:
False
– ifTrue
, usesize
to crop final image -
upscale – default:
False
– if image dimensions are smaller than those insize
, upscale image tosize
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 two basic events:
- 'markdownx.init'
- 'markdownx.update' – also returns 'response' variable containing markdownified text
$('.markdownx').on('markdownx.init', function() {
console.log("INIT");
});
$('.markdownx').on('markdownx.update', function(e, response) {
console.log("UPDATE" + response);
});
Dependencies
- Markdown
- Pillow
- Django
- jQuery
Changelog
v1.6.3
- Corrupted image upload exception
v1.6.2
- Runtest template fix
v1.6.1
- Template render syntax fix
v1.6
- Support for Django's
default_storage
- Fix for missing MARKDOWNX_MARKDOWNIFY_FUNCTION in settings
v1.5
- Possibility to customize image insertion code
v1.4.3
- Markdown abstractable function fix
v1.4.2
- Maintenance release
v1.4.1
- Make rendering the markdown abstractable
v1.4
- Added JS (jQuery) events
- Custom upload url path
- Fix when subclassing MarkdownxWidget
v1.3
- Added Markdown extension configuration setting
v1.2.1
- Fix by Eduard Sukharev: Fix accessing file length in python3
v1.2
- Added custom url path setting MARKDOWNX_URLS_PATH to compile markdown with custom view (i.e. for pre/post altering markdown text)
v1.1.3
- Setup tools fix
v1.1.2
- Critical fix for image upload
v1.1.1
- Package fix
v1.1
- Python 3.3+ support
- Very simple test added just to test python 3 support
v1.0.1
- Moved html logic from FormField to Widget to be able to override model objects other than included MarkdownxModel
- Fixed default value for
MARKDOWNX_EDITOR_RESIZABLE
v1.0.0
- Warning: no backward compatibility
- Admin, Model and Form custom objects
- Django admin styles for compiled markdown
- Settings variables changed:
- MARKDOWNX_MAX_SIZE => MARKDOWNX_IMAGE_MAX_SIZE
- MARKDOWNX_MARKDOWN_KWARGS => MARKDOWNX_MARKDOWN_EXTENSIONS
- MARKDOWNX_MAX_UPLOADSIZE => MARKDOWNX_UPLOAD_MAX_SIZE
- MARKDOWNX_CONTENT_TYPES => MARKDOWNX_UPLOAD_CONTENT_TYPES
v0.4.2
- Path fix by argaen
v0.4.1
- Better editor height updates
- Refresh preview on image upload
- Small JS code fixes
v0.4.0
- editor auto height
v0.3.1
- JS event fix
v0.3.0
- version bump
v0.2.9
- Removed any inlcuded css
- Removed JS markdown compiler (full python support now with Markdown lib)
v0.2.0
- Allow to paste tabs using Tab button
v0.1.4
- package data fix
v0.1.3
- README.md fix on PyPi
v0.1.2
- critical setuptools fix
v0.1.1
- change context name
editor
tomarkdownx_editor
for better consistency
v0.1.0
- init
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.