Package: django-pagedown
Django PagedownAddStack Overflow's "Pagedown" Markdown editorto your Django Admin or custom form.RequirementsVersion >= 2.0.0 ofdjango-pagedownrequires Django 2.1.0 or above (previous versions should support Django all the way back to around 1.1).InstallationGet the code:pip install django-pagedownAddpagedown.apps.PagedownConfigto yourINSTALLED_APPSinsettings.pyConfigure and collectthe static files:python manage.py collectstaticUsageThe widget can be used both inside the django admin or independendly.Inside the Django Admin:If you want to use the pagedown editor in a django admin field, there are numerous possible approaches:To use it inallTextField's in your admin form:fromdjango.contribimportadminfromdjango.dbimportmodelsfrompagedown.widgetsimportAdminPagedownWidgetclassAlbumAdmin(admin.ModelAdmin):formfield_overrides={models.TextField:{'widget':AdminPagedownWidget},}To only use it onparticular fields, first create a form (informs.py):fromdjangoimportformsfrompagedown.widgetsimportAdminPagedownWidgetfrommusic.modelsimportAlbumclassAlbumForm(forms.ModelForm):name=forms.CharField(widget=AdminPagedownWidget())description=forms.CharField(widget=AdminPagedownWidget())classMeta:model=Albumfields="__all__"and in youradmin.py:fromdjango.contribimportadminfromformsimportFooModelFormfrommodelsimportFooModel@admin.register(FooModel)classFooModelAdmin(admin.ModelAdmin):form=FooModelFormfields="__all__"Outside the Django Admin:To use the widget outside of the django admin, first create a form similar to the above but using the basicPagedownWidget:fromdjangoimportformsfrompagedown.widgetsimportPagedownWidgetfrommusic.modelsimportAlbumclassAlbumForm(forms.ModelForm):name=forms.CharField(widget=PagedownWidget())description=forms.CharField(widget=PagedownWidget())classMeta:model=Albumfields=["name","description"]Then define your urls/views:fromdjango.views.genericimportFormViewfromdjango.conf.urlsimportpatterns,urlfrommusic.formsimportAlbumFormurlpatterns=patterns('',url(r'^$',FormView.as_view(template_name="baz.html",form_class=AlbumForm)),)then create the template and load the javascipt and css required to create the editor:<html><head>{{ form.media }}</head><body><form...>{{ form }}</form></body></html>Customizing the WidgetIf you want to customize the widget, the easiest way is to simply extend it:frompagedown.widgetsimportPagedownWidgetclassMyNewWidget(PagedownWidget):template_name='/custom/template.html'classMedia:css={'all':('custom/stylesheets.css',)}js=('custom/javascript.js',)Rendering Markdowncontrib.markdownwasdeprecated in Django 1.5meaning you can no longer use themarkdownfilter in your template by default.@wkcd has a good exampleof how to overcome by installingdjango-markdown-deux:{%extends'base.html'%}{%loadmarkdown_deux_tags%}...<p>{{entry.body|markdown}}</p>...Image UploadsYou can enable image uploads, allowing your users to upload new images to the server and have them automatically inserted into the Pagedown widget (instead of just adding image URLs):To do so:Make sure you have set aMEDIA_URLandMEDIA_ROOTso that uploads will be propertly savedAddPAGEDOWN_IMAGE_UPLOAD_ENABLED=Trueto your settingsInclude the pagedown paths in yoururls.pyso that the upload endpoint is available# ...urlpatterns=[path('',include('pagedown.urls')),# ...]This will add the URL/pagedown/image-upload/endpoint to your project. You cansee the default view that handles the upload hereThe following options are available via your settings to tweak how the image upload works:PAGEDOWN_IMAGE_UPLOAD_PATHcan be used to change the path within your media root (default ispagedown-uploads)PAGEDOWN_IMAGE_UPLOAD_EXTENSIONScan be used to limit the extensions allowed for upload (default isjpg,jpeg,png,webp)PAGEDOWN_IMAGE_UPLOAD_UNIQUEcan be used to ensure all uploads are stored in a uniquely named subfolder, e.g.f748e009-c3cb-40f3-abf2-d103ab0ad259/my-file.png(default isFalse)Check out thepagedown_init.jsscript tosee how the upload is being performed on the client side.ExampleYou can see a fully-fledged example of the widget indjango-pagedown-example