Skip to main content

A GitHub-style markdown editor widget for Django forms

Project description

django-md-editor

A GitHub-style markdown editor widget for Django forms and admin.

PyPI version Python versions Django versions License: MIT Docs

Documentation | PyPI | GitHub

Features

  • GitHub-flavored markdown editor with live preview
  • Toolbar with common formatting actions (headings, bold, italic, code, tables, etc.)
  • Image and file uploads with drag & drop support
  • Light, dark, and auto theme support
  • Django admin integration via one-line mixin
  • Template tag and filter for rendering markdown in templates
  • Pluggable renderer and upload handler architecture
  • Automatic media cleanup for orphaned uploads
  • Management command for bulk orphan detection
  • Zero hard dependencies beyond Django (markdown library is optional)
  • Keyboard shortcuts (Ctrl+B, Ctrl+I, Ctrl+K, etc.)

Installation

pip install django-markdown-widget

Add to your INSTALLED_APPS and include the URLs:

# settings.py
INSTALLED_APPS = [
    ...
    "django_md_editor",
]

# urls.py
from django.urls import include, path

urlpatterns = [
    ...
    path("md-editor/", include("django_md_editor.urls")),
]

For server-side rendering, install a markdown library:

pip install markdown

Quick Start

Form Widget

from django.forms import ModelForm
from django_md_editor import MarkdownEditorWidget

class PostForm(ModelForm):
    class Meta:
        model = Post
        fields = ["title", "content"]
        widgets = {
            "content": MarkdownEditorWidget(),
        }

Django Admin

from django.contrib import admin
from django_md_editor import MarkdownEditorAdminMixin

@admin.register(Post)
class PostAdmin(MarkdownEditorAdminMixin, admin.ModelAdmin):
    list_display = ["title", "created_at"]
    markdown_fields = ["content"]  # omit to apply to all TextFields

Template Rendering

{% load md_editor %}

{# As a filter (recommended) #}
{{ post.content|markdown }}

{# As a tag #}
{% markdown post.content %}

Media Cleanup

from django_md_editor import MarkdownCleanupMixin

class Post(MarkdownCleanupMixin, models.Model):
    content = models.TextField()
    # markdown_cleanup_fields = ["content"]  # optional: limit to specific fields

Enable in settings:

MD_EDITOR = {
    "CLEANUP_MEDIA": True,
}

Bulk cleanup via management command:

python manage.py cleanup_markdown_media --dry-run
python manage.py cleanup_markdown_media

Configuration

All settings are optional and go under MD_EDITOR in your Django settings:

MD_EDITOR = {
    # Pluggable backend classes
    "RENDERER_CLASS": "django_md_editor.renderers.DefaultRenderer",
    "UPLOAD_HANDLER_CLASS": "django_md_editor.uploads.DefaultUploadHandler",

    # Toolbar buttons
    "TOOLBAR": [
        "heading", "bold", "italic", "strikethrough", "separator",
        "quote", "code", "code-block", "link", "image", "separator",
        "ordered-list", "unordered-list", "task-list", "separator",
        "horizontal-rule", "table", "details", "separator",
        "highlight", "superscript", "subscript", "separator",
        "attach", "mention", "ref", "separator",
        "undo", "redo", "fullscreen",
    ],

    # Upload settings
    "ALLOWED_UPLOAD_TYPES": ["image/png", "image/jpeg", "image/gif", "image/webp"],
    "MAX_UPLOAD_SIZE": 10 * 1024 * 1024,  # 10 MB
    "UPLOAD_PATH": "md-editor/uploads/%Y/%m/",

    # Editor defaults
    "DEFAULT_HEIGHT": "300px",
    "PLACEHOLDER": "Add your comment here...",
    "THEME": "auto",  # "light", "dark", or "auto"

    # Security
    "REQUIRE_AUTH": True,

    # Media cleanup
    "CLEANUP_MEDIA": False,
}

Custom Renderer

from django_md_editor import BaseRenderer

class MyRenderer(BaseRenderer):
    def render(self, markdown_text: str) -> str:
        import markdown_it
        md = markdown_it.MarkdownIt()
        return md.render(markdown_text)
MD_EDITOR = {
    "RENDERER_CLASS": "myapp.renderers.MyRenderer",
}

Custom Upload Handler

from django_md_editor import BaseUploadHandler

class S3UploadHandler(BaseUploadHandler):
    def validate(self, file):
        # your validation logic
        pass

    def save(self, file) -> str:
        # save to S3 and return the URL
        return url
MD_EDITOR = {
    "UPLOAD_HANDLER_CLASS": "myapp.uploads.S3UploadHandler",
}

Development

git clone https://github.com/ganiyevuz/django-md-editor.git
cd django-md-editor
uv sync --group dev
make test
make lint

Run the example app:

cd example
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver

License

MIT License. See LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_markdown_widget-1.0.0.tar.gz (155.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_markdown_widget-1.0.0-py3-none-any.whl (37.5 kB view details)

Uploaded Python 3

File details

Details for the file django_markdown_widget-1.0.0.tar.gz.

File metadata

File hashes

Hashes for django_markdown_widget-1.0.0.tar.gz
Algorithm Hash digest
SHA256 107b63c91c70a1ee6cf527b35fb1969a41df3a1d537a225666bba739bb994df1
MD5 fedb5a85ec5d333b3936db1eaceaf494
BLAKE2b-256 965d17867fd3ec01ac995b874abb7fb6536acdefa62162880326ce70b2056f1a

See more details on using hashes here.

File details

Details for the file django_markdown_widget-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_markdown_widget-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 411fd5596dbf6d906b29dd74660ad196cec91d445f8a362af9da3232d13a5c13
MD5 ea6c5595b8cc8791db4fb5df5544d6c6
BLAKE2b-256 06060942e69710d3afa1a5195e6374b551dce3a69d0e9d3812c282e5bc6d9e8d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page