{"id":13415659,"url":"https://github.com/agusmakmun/django-markdown-editor","last_synced_at":"2026-04-18T14:06:13.686Z","repository":{"id":37933407,"uuid":"77475218","full_name":"agusmakmun/django-markdown-editor","owner":"agusmakmun","description":"Awesome Django Markdown Editor, supported for Bootstrap \u0026 Semantic-UI","archived":false,"fork":false,"pushed_at":"2024-11-14T17:41:25.000Z","size":7618,"stargazers_count":826,"open_issues_count":35,"forks_count":1343,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-11-24T17:51:56.715Z","etag":null,"topics":["ace","bootstrap","content-editor","django","django-markdown-editor","imgur","markdown","markdown-editor","martor","python","python-markdown","rich-text-editor","semantic-ui","wysiwyg","wysiwyg-editor"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/agusmakmun.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["agusmakmun"],"ko_fi":null,"liberapay":null,"issuehunt":null,"custom":["https://www.paypal.me/summonagus"]}},"created_at":"2016-12-27T18:33:34.000Z","updated_at":"2024-11-22T15:33:33.000Z","dependencies_parsed_at":"2023-02-10T15:45:15.311Z","dependency_job_id":"8ea24d28-a3cf-4112-b08d-3b6e1e1d86eb","html_url":"https://github.com/agusmakmun/django-markdown-editor","commit_stats":{"total_commits":352,"total_committers":44,"mean_commits":8.0,"dds":0.5170454545454546,"last_synced_commit":"5dbc9f1f7e10931472a7309b237c66c2ecb33045"},"previous_names":[],"tags_count":101,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agusmakmun%2Fdjango-markdown-editor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agusmakmun%2Fdjango-markdown-editor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agusmakmun%2Fdjango-markdown-editor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/agusmakmun%2Fdjango-markdown-editor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/agusmakmun","download_url":"https://codeload.github.com/agusmakmun/django-markdown-editor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248505873,"owners_count":21115354,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ace","bootstrap","content-editor","django","django-markdown-editor","imgur","markdown","markdown-editor","martor","python","python-markdown","rich-text-editor","semantic-ui","wysiwyg","wysiwyg-editor"],"created_at":"2024-07-30T21:00:51.146Z","updated_at":"2025-04-12T01:53:03.714Z","avatar_url":"https://github.com/agusmakmun.png","language":"JavaScript","readme":"## martor [![pypi version][1]][2] [![paypal donation][3]][4]\n\n[![license][5]][6] [![python version][7]][8] [![django version][9]][10] [![build][11]][12] [![black][18]][19]\n\n**Martor** is a Markdown Editor plugin for Django, supported for _Bootstrap_ \u0026 _Semantic-UI_.\n\n\n### Features\n\n* Live Preview\n* Integrated with [_Ace Editor_](https://ace.c9.io)\n* Supported with [_Bootstrap_](https://getbootstrap.com) and [_Semantic-UI_](https://semantic-ui.com)\n* Supported Multiple Fields [_fixed this issue_](https://github.com/agusmakmun/django-markdown-editor/issues/3)\n* Upload Images to imgur.com _(via API)_ and [custom uploader][13]\n* Direct Mention users `@[username]` - _(requires user to logged in)_.\n* Supports embed/iframe video from (Youtube, Vimeo, Dailymotion, Yahoo, Veoh, \u0026 Metacafe)\n* Spellchecking (only supports US English at this time)\n* Emoji `:emoji_name:` + Cheat sheets\n* Martor Commands Reference\n* Supports Django Admin\n* Toolbar Buttons\n* Highlight `pre`\n* Custom ID Attributes (Add custom IDs to any text element using `{#custom-id}` syntax, e.g., `# Heading1 {#my-h1-id}`, for easy linking and navigation.\n\n\n### Preview\n\n![editor](https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/master/.etc/images/bootstrap/martor-editor.png)\n\n![preview](https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/master/.etc/images/bootstrap/martor-preview.png)\n\n\n### Requirements\n\n* `Django\u003e=3.2`\n* `Markdown\u003e=3.0`\n* `requests\u003e=2.12.4`\n* `bleach`\n\n\n### Installation\n\nMartor is available directly from [PyPI][2]:\n\n**1.** Installing the package.\n\n```\n$ pip install martor\n```\n\n\n**2.** Don't forget to add `'martor'` to your `'INSTALLED_APPS'` setting _(without migrations)_.\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    ....\n    'martor',\n]\n```\n\n\n**3.** Add url pattern to your `urls.py.`\n\n```python\n# urls.py\nurlpatterns = [\n    ...\n    path('martor/', include('martor.urls')),\n]\n```\n\n\n**4.** Collect martor's static files in your `STATIC_ROOT` folder.\n\n```\n./manage.py collectstatic\n```\n\n\n### Setting Configurations `settings.py`\n\nPlease register your application at https://api.imgur.com/oauth2/addclient\nto get `IMGUR_CLIENT_ID` and `IMGUR_API_KEY`.\n\n```python\n# Choices are: \"semantic\", \"bootstrap\"\nMARTOR_THEME = 'bootstrap'\n\n# Global martor settings\n# Input: string boolean, `true/false`\nMARTOR_ENABLE_CONFIGS = {\n    'emoji': 'true',        # to enable/disable emoji icons.\n    'imgur': 'true',        # to enable/disable imgur/custom uploader.\n    'mention': 'false',     # to enable/disable mention\n    'jquery': 'true',       # to include/revoke jquery (require for admin default django)\n    'living': 'false',      # to enable/disable live updates in preview\n    'spellcheck': 'false',  # to enable/disable spellcheck in form textareas\n    'hljs': 'true',         # to enable/disable hljs highlighting in preview\n}\n\n# To show the toolbar buttons\nMARTOR_TOOLBAR_BUTTONS = [\n    'bold', 'italic', 'horizontal', 'heading', 'pre-code',\n    'blockquote', 'unordered-list', 'ordered-list',\n    'link', 'image-link', 'image-upload', 'emoji',\n    'direct-mention', 'toggle-maximize', 'help'\n]\n\n# To setup the martor editor with title label or not (default is False)\nMARTOR_ENABLE_LABEL = False\n\n# Disable admin style when using custom admin interface e.g django-grappelli (default is True)\nMARTOR_ENABLE_ADMIN_CSS = True\n\n# Imgur API Keys\nMARTOR_IMGUR_CLIENT_ID = 'your-client-id'\nMARTOR_IMGUR_API_KEY   = 'your-api-key'\n\n# Markdownify\nMARTOR_MARKDOWNIFY_FUNCTION = 'martor.utils.markdownify' # default\nMARTOR_MARKDOWNIFY_URL = '/martor/markdownify/' # default\n\n# Delay in milliseconds to update editor preview when in living mode.\nMARTOR_MARKDOWNIFY_TIMEOUT = 0 # update the preview instantly\n# or:\nMARTOR_MARKDOWNIFY_TIMEOUT = 1000 # default\n\n# Markdown extensions (default)\nMARTOR_MARKDOWN_EXTENSIONS = [\n    'markdown.extensions.extra',\n    'markdown.extensions.nl2br',\n    'markdown.extensions.smarty',\n    'markdown.extensions.fenced_code',\n    'markdown.extensions.sane_lists',\n\n    # Custom markdown extensions.\n    'martor.extensions.urlize',\n    'martor.extensions.del_ins',      # ~~strikethrough~~ and ++underscores++\n    'martor.extensions.mention',      # to parse markdown mention\n    'martor.extensions.emoji',        # to parse markdown emoji\n    'martor.extensions.mdx_video',    # to parse embed/iframe video\n    'martor.extensions.escape_html',  # to handle the XSS vulnerabilities\n    \"martor.extensions.mdx_add_id\",  # to parse id like {#this_is_id}\n]\n\n# Markdown Extensions Configs\nMARTOR_MARKDOWN_EXTENSION_CONFIGS = {}\n\n# Markdown urls\nMARTOR_UPLOAD_URL = '' # Completely disable the endpoint\n# or:\nMARTOR_UPLOAD_URL = '/martor/uploader/' # default\n\nMARTOR_SEARCH_USERS_URL = '' # Completely disables the endpoint\n# or:\nMARTOR_SEARCH_USERS_URL = '/martor/search-user/' # default\n\n# Markdown Extensions\n# MARTOR_MARKDOWN_BASE_EMOJI_URL = 'https://www.webfx.com/tools/emoji-cheat-sheet/graphics/emojis/'     # from webfx\nMARTOR_MARKDOWN_BASE_EMOJI_URL = 'https://github.githubassets.com/images/icons/emoji/'                  # default from github\n# or:\nMARTOR_MARKDOWN_BASE_EMOJI_URL = ''  # Completely disables the endpoint\nMARTOR_MARKDOWN_BASE_MENTION_URL = 'https://python.web.id/author/'                                      # please change this to your domain\n\n# If you need to use your own themed \"bootstrap\" or \"semantic ui\" dependency\n# replace the values with the file in your static files dir\nMARTOR_ALTERNATIVE_JS_FILE_THEME = \"semantic-themed/semantic.min.js\"   # default None\nMARTOR_ALTERNATIVE_CSS_FILE_THEME = \"semantic-themed/semantic.min.css\" # default None\nMARTOR_ALTERNATIVE_JQUERY_JS_FILE = \"jquery/dist/jquery.min.js\"        # default None\n\n# URL schemes that are allowed within links\nALLOWED_URL_SCHEMES = [\n    \"file\", \"ftp\", \"ftps\", \"http\", \"https\", \"irc\", \"mailto\",\n    \"sftp\", \"ssh\", \"tel\", \"telnet\", \"tftp\", \"vnc\", \"xmpp\",\n]\n\n# https://gist.github.com/mrmrs/7650266\nALLOWED_HTML_TAGS = [\n    \"a\", \"abbr\", \"b\", \"blockquote\", \"br\", \"cite\", \"code\", \"command\",\n    \"dd\", \"del\", \"dl\", \"dt\", \"em\", \"fieldset\", \"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\",\n    \"hr\", \"i\", \"iframe\", \"img\", \"input\", \"ins\", \"kbd\", \"label\", \"legend\",\n    \"li\", \"ol\", \"optgroup\", \"option\", \"p\", \"pre\", \"small\", \"span\", \"strong\",\n    \"sub\", \"sup\", \"table\", \"tbody\", \"td\", \"tfoot\", \"th\", \"thead\", \"tr\", \"u\", \"ul\"\n]\n\n# https://github.com/decal/werdlists/blob/master/html-words/html-attributes-list.txt\nALLOWED_HTML_ATTRIBUTES = [\n    \"alt\", \"class\", \"color\", \"colspan\", \"datetime\",  # \"data\",\n    \"height\", \"href\", \"id\", \"name\", \"reversed\", \"rowspan\",\n    \"scope\", \"src\", \"style\", \"title\", \"type\", \"width\"\n]\n```\n\nCheck this setting is not set else csrf will not be sent over ajax calls:\n\n```python\nCSRF_COOKIE_HTTPONLY = False\n```\n\n\n### Usage\n\n\n#### Model\n\n```python\nfrom django.db import models\nfrom martor.models import MartorField\n\nclass Post(models.Model):\n    description = MartorField()\n```\n\n\n#### Form\n\n```python\nfrom django import forms\nfrom martor.fields import MartorFormField\n\nclass PostForm(forms.Form):\n    description = MartorFormField()\n```\n\n\n#### Admin\n\n```python\nfrom django.db import models\nfrom django.contrib import admin\n\nfrom martor.widgets import AdminMartorWidget\n\nfrom yourapp.models import YourModel\n\nclass YourModelAdmin(admin.ModelAdmin):\n    formfield_overrides = {\n        models.TextField: {'widget': AdminMartorWidget},\n    }\n\nadmin.site.register(YourModel, YourModelAdmin)\n```\n\n\n#### Template Renderer\n\nSimply safely parse markdown content as html output by loading templatetags from `martor/templatetags/martortags.py`.\n\n```html\n{% load martortags %}\n{{ field_name|safe_markdown }}\n\n# example\n{{ post.description|safe_markdown }}\n```\n\n\nDon't miss to include the required css \u0026 js files before use.\nYou can take a look at this folder [martor_demo/app/templates][14] for more details.\nThe below example is a one of the way to implement it when you choose the `MARTOR_THEME = 'bootstrap'`:\n\n```html\n{% extends \"bootstrap/base.html\" %}\n{% load static %}\n{% load martortags %}\n\n{% block css %}\n  \u003clink href=\"{% static 'plugins/css/ace.min.css' %}\" type=\"text/css\" media=\"all\" rel=\"stylesheet\" /\u003e\n  \u003clink href=\"{% static 'martor/css/martor.bootstrap.min.css' %}\" type=\"text/css\" media=\"all\" rel=\"stylesheet\" /\u003e\n{% endblock %}\n\n{% block content %}\n  \u003cdiv class=\"martor-preview\"\u003e\n    \u003ch1\u003eTitle: {{ post.title }}\u003c/h1\u003e\n    \u003cp\u003e\u003cb\u003eDescription:\u003c/b\u003e\u003c/p\u003e\n    \u003chr /\u003e\n    {{ post.description|safe_markdown }}\n  \u003c/div\u003e\n{% endblock %}\n\n{% block js %}\n  \u003cscript type=\"text/javascript\" src=\"{% static 'plugins/js/highlight.min.js' %}\"\u003e\u003c/script\u003e\n  \u003cscript\u003e\n    $('.martor-preview pre').each(function(i, block){\n        hljs.highlightBlock(block);\n    });\n  \u003c/script\u003e\n{% endblock %}\n```\n\n\n#### Template Editor Form\n\nDifferent with *Template Renderer*, the *Template Editor Form* have more css \u0026 javascript dependencies.\n\n```html\n{% extends \"bootstrap/base.html\" %}\n{% load static %}\n\n{% block css %}\n  \u003clink href=\"{% static 'plugins/css/ace.min.css' %}\" type=\"text/css\" media=\"all\" rel=\"stylesheet\" /\u003e\n  \u003clink href=\"{% static 'plugins/css/resizable.min.css' %}\" type=\"text/css\" media=\"all\" rel=\"stylesheet\" /\u003e\n  \u003clink href=\"{% static 'martor/css/martor.bootstrap.min.css' %}\" type=\"text/css\" media=\"all\" rel=\"stylesheet\" /\u003e\n{% endblock %}\n\n{% block content %}\n  \u003cform class=\"form\" method=\"post\"\u003e{% csrf_token %}\n    \u003cdiv class=\"form-group\"\u003e\n      {{ form.title }}\n    \u003c/div\u003e\n    \u003cdiv class=\"form-group\"\u003e\n      {{ form.description }}\n    \u003c/div\u003e\n    \u003cdiv class=\"form-group\"\u003e\n      \u003cbutton class=\"btn btn-success\"\u003e\n        \u003ci class=\"save icon\"\u003e\u003c/i\u003e Save Post\n      \u003c/button\u003e\n    \u003c/div\u003e\n  \u003c/form\u003e\n{% endblock %}\n\n{% block js %}\n  \u003cscript type=\"text/javascript\" src=\"{% static 'plugins/js/ace.js' %}\"\u003e\u003c/script\u003e\n  \u003cscript type=\"text/javascript\" src=\"{% static 'plugins/js/mode-markdown.js' %}\"\u003e\u003c/script\u003e\n  \u003cscript type=\"text/javascript\" src=\"{% static 'plugins/js/ext-language_tools.js' %}\"\u003e\u003c/script\u003e\n  \u003cscript type=\"text/javascript\" src=\"{% static 'plugins/js/theme-github.js' %}\"\u003e\u003c/script\u003e\n  \u003cscript type=\"text/javascript\" src=\"{% static 'plugins/js/typo.js' %}\"\u003e\u003c/script\u003e\n  \u003cscript type=\"text/javascript\" src=\"{% static 'plugins/js/spellcheck.js' %}\"\u003e\u003c/script\u003e\n  \u003cscript type=\"text/javascript\" src=\"{% static 'plugins/js/highlight.min.js' %}\"\u003e\u003c/script\u003e\n  \u003cscript type=\"text/javascript\" src=\"{% static 'plugins/js/resizable.min.js' %}\"\u003e\u003c/script\u003e\n  \u003cscript type=\"text/javascript\" src=\"{% static 'plugins/js/emojis.min.js' %}\"\u003e\u003c/script\u003e\n  \u003cscript type=\"text/javascript\" src=\"{% static 'martor/js/martor.bootstrap.min.js' %}\"\u003e\u003c/script\u003e\n{% endblock %}\n```\n\n\n### Custom Uploader\n\nIf you want to save the images uploaded to your storage,\n**Martor** also provides a way to handle this. Please checkout this [WIKI][13]\n\n\n### Test Martor from this Repository\n\nAssuming you are already setup with a virtual environment (virtualenv):\n\n```\n$ git clone https://github.com/agusmakmun/django-markdown-editor.git\n$ cd django-markdown-editor/ \u0026\u0026 python setup.py install\n$ cd martor_demo/\n$ python manage.py makemigrations \u0026\u0026 python manage.py migrate\n$ python manage.py runserver\n```\n\n\nCheckout at http://127.0.0.1:8000/simple-form/ on your browser.\n\n\n### Martor Commands Reference\n\n![command reference](https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/master/.etc/images/bootstrap/martor-guide.png)\n\n\n### Notes\n\n**Martor** was inspired by these great projects: [django-markdownx][15], [Python Markdown][16] and [Online reStructuredText editor][17].\n\n\n[1]: https://img.shields.io/pypi/v/martor.svg\n[2]: https://pypi.python.org/pypi/martor\n\n[3]: https://img.shields.io/badge/donate-paypal-blue\n[4]: https://www.paypal.com/paypalme/summonagus\n\n[5]: https://img.shields.io/badge/license-GNUGPLv3-blue.svg\n[6]: https://raw.githubusercontent.com/agusmakmun/django-markdown-editor/master/LICENSE\n\n[7]: https://img.shields.io/pypi/pyversions/martor.svg\n[8]: https://pypi.python.org/pypi/martor\n\n[9]: https://img.shields.io/badge/Django-3.2%20%3E=%204.2-green.svg\n[10]: https://www.djangoproject.com\n\n[11]: https://img.shields.io/github/actions/workflow/status/agusmakmun/django-markdown-editor/run-tests.yml?branch=master\n[12]: https://github.com/agusmakmun/django-markdown-editor/actions/workflows/run-tests.yml\n\n[13]: https://github.com/agusmakmun/django-markdown-editor/wiki\n[14]: https://github.com/agusmakmun/django-markdown-editor/tree/master/martor_demo/app/templates\n[15]: https://github.com/adi-/django-markdownx\n[16]: https://github.com/waylan/Python-Markdown\n[17]: https://rsted.info.ucl.ac.be\n\n[18]: https://img.shields.io/badge/code%20style-black-000000.svg\n[19]: https://github.com/ambv/black\n","funding_links":["https://github.com/sponsors/agusmakmun","https://www.paypal.me/summonagus","https://www.paypal.com/paypalme/summonagus"],"categories":["Third-Party Packages","JavaScript","Markdown"],"sub_categories":["Editors"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagusmakmun%2Fdjango-markdown-editor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fagusmakmun%2Fdjango-markdown-editor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fagusmakmun%2Fdjango-markdown-editor/lists"}