Integrating TinyMCE with Django
Many people often want What You See Is What You Get (WYSIWYG) editors when creating content from within their web applications. This can be either in the Django admin control panel or for the end user. One of the most flexible and useful of the WYSIWYG editors currently available is TinyMCE due to its extensive plugin library and robust feature set. Integration with Django is relatively simple given that you extend the functionality of built in classes.
The first thing we will need to do is create a custom widget from forms.Textarea found in the django.forms module. We accomplish this by inheriting the Textarea class and overriding the constructor and render methods. Defining the relative path (on your web server) to the TInyMCE javascript source is also required here. So be aware that you will need to change that path to suite your environment. You may also want to change the content_css variable to include your sites’ main CSS file. The following is the source code for widgets.py which should be place in your projects root directory.
from django import forms from django.conf import settings from django.utils.safestring import mark_safe class AdvancedEditor(forms.Textarea): class Media: js = ('/images/tiny_mce/tiny_mce.js',) def __init__(self, language=None, attrs=None): self.language = language or settings.LANGUAGE_CODE[:2] self.attrs = {'class': 'advancededitor'} if attrs: self.attrs.update(attrs) super(AdvancedEditor, self).__init__(attrs) def render(self, name, value, attrs=None): rendered = super(AdvancedEditor, self).render(name, value, attrs) return rendered + mark_safe(u''' <script type="text/javascript"> tinyMCE.init({ mode: "textareas", theme: "advanced", plugins: "advhr,table,emotions,media,insertdatetime,directionality", theme_advanced_toolbar_align: "left", theme_advanced_toolbar_location: "top", theme_advanced_buttons1:"bold,italic,underline,strikethrough,sub,sup,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,formatselect,fontselect,fontsizeselect", theme_advanced_buttons2:"bullist,numlist,outdent,indent,ltr,rtl,separator,link,unlink,anchor,image,separator,table,insertdate,inserttime,advhr,emotions,media,charmap,separator,undo,redo", theme_advanced_buttons3: "", content_css: "images/style.css", height: "350px", width: "653px" }); </script>''')
Now we need to create our form which enables us to use the new widget. Just as an example, we will make a form for use in the Django admin control panel: to show how to use the widget in model admin classes. We simply create a standard ModelForm class as normal, except that the field you wish to use as your WYWISWYG editor must be a CharField. In my example, I create a simple form for use in the Django admin control panel to allow users to write news articles with advanced editing capabilities. You can do this for any class within any of your forms.py files in either the projects’ main directory or within an application directory. The code is as follows:
from django import forms from django.db.models import get_model from django.contrib.auth.models import User from sodclan.widgets import AdvancedEditor from sodclan.models import Article class ArticleModelAdminForm(forms.ModelForm): title = forms.CharField(max_length=50) author = forms.ModelChoiceField(queryset=User.objects.all()) content = forms.CharField(widget=AdvancedEditor()) class Meta: model = Article
As you can see, we imported the AdvancedEditor class we created earlier including the Article class which represents the model we wish to associate the form with. Notice the widget for the content field has been set to AdvancedEditor(). Now we can modify our ModelAdmin class to utilize our form and thus allow us to use TinyMCE within the Django admin control panel. In my admin.py file, the code is as follows:
from django.contrib import admin from sodclan.forms import ArticleModelAdminForm from sodclan.models import * class ArticleAdmin(admin.ModelAdmin): list_display = ('title', 'author', 'date',) search_fields = ['title',] date_hierarchy = 'date' form = ArticleModelAdminForm admin.site.register(Article, ArticleAdmin)
Here we import the model admin form we created in the last code segment. The only difference here from a normal ModelAdmin class is that we define the form field. We set this field to our form class, in this case: ArticleModelAdminForm. When finally run, the result will look something like this:
Remember that we used an example using the Django admin control panel just to show how to do it. But you can take this concept and apply it anywhere in your Django web application where you can utilize forms. Which allows you to make very rich, usable web applications very easily. Hope this helps, comment with any questions or remarks.


I followed your setup but it doesn’t work on my admin text area.
Could you give more hints on how you set up?
Do you use django-tinymce?
thanks!
Hmm… I read blogs on a similar topic, but i never visited your blog. I added it to favorites and i’ll be your constant reader.
@Webber: No thats literatly exactly how I did it and no I did not use django-tinymce this is entirely my implementation. What exactly doesnt work? If you notice WordPress is annoying and doesnt format my HTML tags correctly and instead escapes them so thats one thing you will have to fix on your own which may be a factor in why its not working perhaps?
Hello there! Thanks for your widget, it works great while there is no need to have two text areas with widget. Otherwise no data sent to server in POST.
I modified your code in this way:
in forms.py i have one model with two fields:
start_text = forms.CharField(widget=AdvancedEditor(attrs={‘id’:'start_text’}), required=False)
finish_text = forms.CharField(widget=AdvancedEditor(attrs={‘id’:'finish_text’}), required=False)
in widgets.py where i store advancededitor:
return rendered + mark_safe(u”’
;
tinyMCE.settings = {
mode: “textareas”,
theme: “advanced”,
..some content skipped……
content_css: “/media/css/main.css”,
height: “350px”,
width: “653px”
};
tinyMCE.execCommand(‘mceAddControl’, true, ‘%s’);
”’ % self.attrs["id"])
And now it’s ok
Its still not working. I tried to work as you told but i am not getting the output. If you can solve the problem for me then i can mail you the code.
Please Help Me Out!!
I’m usually not the guy to submit my opinion on people’s write ups, but for this write up I just had to do it. I’ve been browsing through your blog a lot recently and I’m super impressed, I think you might potentially become a main voices for your niche. Not sure what your schedule is like in life, but if you started commiting more effort to posting on this site, I’d guess you would start receiving a bunch of traffic eventually. With affiliate stuff, it might become a great reserve revenue stream. Just a concept to think about. Good luck!
Hah, well I appreciate it. I’ve been quite busy as of late but I was considering writing a few things in the coming months, so definitely stay tuned if your interested.
To all those having issues with the tutorial still, my hunch is that something changed in one of the newer versions of Django and this tutorial needs to be mended as such. I will look into it sometime soon hopefully.