django-markdownfield 
A Django field that renders Markdown to sanitized HTML and stores both in your database.
Your text is stored in a MarkdownField. When the model is saved, django-markdownfield renders it
with markdown-it-py (by default),
sanitizes it with nh3, and stores the result in a
RenderedMarkdownField.
The rendering backend is swappable. Bundles EasyMDE (v2.20.0) for admin and frontend forms.
Installation
pip install django-markdownfield
Add to INSTALLED_APPS and configure the rendering backend:
INSTALLED_APPS = [
'markdownfield',
...
'django.contrib.staticfiles',
]
MARKDOWNFIELD_BACKEND = 'markdownfield.backends.markdownit'
Backend configuration (plugins, HTML passthrough, custom backends) is covered in docs/backends.md. A python-markdown backend is also included (pip install django-markdownfield[pymarkdown]).
To enable the admin preview endpoint, add the URL configuration:
urlpatterns = [
path('markdownfield/', include('markdownfield.urls')),
...
]
Quick start
Add a MarkdownField and a paired RenderedMarkdownField to your model:
from django.db import models
from markdownfield.models import MarkdownField, RenderedMarkdownField
from markdownfield.validators import VALIDATOR_STANDARD
class Page(models.Model):
text = MarkdownField(rendered_field='text_rendered', validator=VALIDATOR_STANDARD)
text_rendered = RenderedMarkdownField()
Whenever your model is saved, the RenderedMarkdownField will be updated automatically.
Display in templates
To display the rendered markdown in your template, just display the RenderedMarkdownField like any other field.
{{ page.text_rendered }}
If you don't want to use a RenderedMarkdownField, use the template filter to render raw Markdown in your templates directly:
{% load markdownfield %}
{{ page.text|render_markdown }}
{{ page.text|render_markdown:"classy" }}
The argument is a validator name. Defaults to standard.
Render in Python
from markdownfield.rendering import render_markdown
from markdownfield.validators import VALIDATOR_STANDARD
html = render_markdown('**bold**', VALIDATOR_STANDARD)
Validators
Validators control which HTML tags and attributes survive sanitization, and which toolbar buttons appear in the editor.
| Validator | Tags | Use case |
|---|---|---|
VALIDATOR_STANDARD |
All standard Markdown tags | General content |
VALIDATOR_CLASSY |
Standard + class on links/images, data-* attributes |
Styled content |
VALIDATOR_NO_IMAGES |
Standard without images | User-generated content |
VALIDATOR_BASIC |
Inline only: bold, italic, strikethrough, code, links | Comments, bios |
VALIDATOR_NULL |
No sanitization | Dangerous. Allows XSS. |
Full details + custom validators are covered in docs/validators.md.
Editor
The EasyMDE editor is enabled automatically in admin and frontend ModelForms.
For frontend forms, you will need to include the form media in your template:
<head>
{{ form.media.css }}
</head>
<body>
<form method="post">
{% csrf_token %}
{{ form }}
<button type="submit">Save</button>
</form>
{{ form.media.js }}
</body>
Disable per-field with use_editor=False (frontend) or use_admin_editor=False (admin).
EasyMDE options can be customized by overriding the widget in your form:
from markdownfield.widgets import MDEWidget
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['text']
widgets = {
'text': MDEWidget(options={'toolbar': ['bold', 'italic', 'link']}),
}
Link processing
These settings control post-sanitization link handling. They apply regardless of which backend is used.
| Setting | Default | Description |
|---|---|---|
MARKDOWNFIELD_MARK_EXTERNAL_LINKS |
True |
Add target="_blank" and class="external" to external links. |
MARKDOWNFIELD_INTERNAL_URL |
None |
Your site's URL or a list of URLs (e.g. 'https://example.com' or ['https://example.com', 'https://cdn.example.com']). Links matching these are treated as internal. Without it, all links are treated as external. |
MARKDOWNFIELD_BLOCKED_LINK_DOMAINS |
[] |
List of domains whose links are stripped (link text preserved). |
Management commands
rerender_markdown - re-renders all stored Markdown into their paired rendered fields. Run after upgrading django-markdownfield, changing validators, or switching backends.
python manage.py rerender_markdown
python manage.py rerender_markdown --dry-run
Further reading
- Backends - switching backends, python-markdown support, custom backends, plugins
- Validators - built-in validators, creating custom validators
License
MIT. See LICENSE.
Release files for django-markdownfield 0.21.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_markdownfield-0.21.1.tar.gz | 184.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_markdownfield-0.21.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 323.2 kB
Release files / django_markdownfield-0.21.1.tar.gz
| Download URL | django_markdownfield-0.21.1.tar.gz |
|---|---|
| Size | 184.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f869a23241aae7a049096c5d05dff522dc3b764bd024f567dac997a08fe2ae54
|
|
BLAKE2b-256 checksum How to use checksums |
5bd91b58dfc3f96132674195554ba92e34e0107103a3f30ff956492eec0ab677
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.
Transparency logRelease files / django_markdownfield-0.21.1-py3-none-any.whl
| Download URL | django_markdownfield-0.21.1-py3-none-any.whl |
|---|---|
| Size | 138.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f665f9957dd48411c3c51f3f041dd51d0d8af8ec48b07190b214e9ddf0144a2d
|
|
BLAKE2b-256 checksum How to use checksums |
c07381e81e8e96af7d4b4f8e0689c69d9a6ecfe20ce69068eaff439aaaa83f51
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.
Transparency log