Recently I’ve been looking for a useful WYSIWYM editor to be used in Django’s admin interface. Thanks to the awesome admin being backed by the forms module it’s rather easy to replace a form field widget with a custom widget.
Although it’s more or less the defacto standard, I’m not going to use TinyMCE this time, partly because it feels a bit like bloatware and partly because it’s not based on jQuery — the JavaScript framework of choice of the project where I also want to use it: django-page-cms. The editor I’m going to use is WYMeditor because it provides authors some helpers to write sane (X)HTML instead of hiding it away while not leaving them with a blank textarea.
The widget
To use the following widget you need to download the source files of WYMedtior first and put them in the directory you specified in the MEDIA_ROOT setting of your Django-based site. So your MEDIA_ROOT directory should now contain a 'jquery' and a 'wymeditor' directory.
Also, copy the following code to a place of your convenience, e.g. the widgets.py of the Django app you are going to add the WYMeditor functionality to.
from django import forms from django.conf import settings from django.utils.safestring import mark_safe class WYMEditor(forms.Textarea): class Media: js = ( 'jquery/jquery.js', 'wymeditor/jquery.wymeditor.pack.js', ) def __init__(self, language=None, attrs=None): self.language = language or settings.LANGUAGE_CODE[:2] self.attrs = {'class': 'wymeditor'} if attrs: self.attrs.update(attrs) super(WYMEditor, self).__init__(attrs) def render(self, name, value, attrs=None): rendered = super(WYMEditor, self).render(name, value, attrs) return rendered + mark_safe(u'''<script type="text/javascript"> jQuery('#id_%s').wymeditor({ updateSelector: '.submit-row input[type=submit]', updateEvent: 'click', lang: '%s', }); </script>''' % (name, self.language))
The WYMEditor widget inherits most of its features from the default forms.Textarea widget and only adds a small bit of JavaScript to initialize in the browser. The inner Media class does all the hard work of adding the correct path to WYMEditor’s source files to the admin template.
The form
Next you need to create a ModelForm subclass that will later be used by the admin as the default form while rendering the edit page. You are again free to put it anywhere in your files as long as you are able to import it. In this case let’s add it to the forms.py of your app, a good place to store form classes.
Please note you need to customize some parts of the following snippet to match your app:
- The second line needs to successfully import the WYMEditor widget
-
Line five should have the name of the field you want to apply the WYMeditor to, in this example the model field
bodywould get it. - The last line uses a nifty tool of Django that loads a model without the need to import it. In fact you just need to give it the lowercase name of the app and the lowercase name of the model.
from django import forms from django.db.models import get_model from yourapp.widgets import WYMEditor class ArticleAdminModelForm(forms.ModelForm): body = forms.CharField(widget=WYMEditor()) class Meta: model = get_model('yourapp', 'article')
Assembling
Now open the 'admin.py' of your app to hook that ModelForm up with the admin interface. First import your ModelForm subclass. Then set the class attribute of the ModelAdmin subclass called form to the form subclass you just imported. Finally register your custom admin class and your model with the default admin site.
from django.contrib import admin from django.db.models import get_model from yourapp.forms import ArticleAdminModelForm class ArticleAdmin(admin.ModelAdmin): # .. form = ArticleAdminModelForm admin.site.register(get_model('yourapp', 'article'), ArticleAdmin)
That’s it for today, I hope everything works for you. Let me know what you think.
comments
nice articel - I´ve been thinking to switch from TinyMCE to WYMEditor for a while and I might give it a try now.
one note: shouldn´t it be
body = forms.TextField(widget=WYMEditor())
instead of
body = forms.CharField(widget=WYMEditor())
sorry, my mistake. your script works fine. I just had to add "from django import forms" for the second script (the one where YourAdminModelForm is defined).
Never heard of WYMEditor. Looks great.
Works great, thant you for this tip.
Any chance someone could post a public site/demo page that is using this?
Any particular reason why not using TinyMCE?
I found TinyMCE being quite easy to integrate...
OMTV: from my point of view, TinyMCE is easy to integrate but people have too many possibilites to do things wrong. even when adding some kind of "custom cleanup", editors might just not see their mistakes (yes, you could still use something like beautifulsoup in the background). with WYMEditor, it´s a lot better, because the structure of the document is obvious. on the other hand, WYMEditor lacks some basic features like a fullscreen edit-mode (which is important when you have a longer text). moreover, selected containers/classes are not highlighted. also, the given themes are horrible.
for now, I´m sticking with TinyMCE - but if WYMEditor get´s a little better, I´ll definitely switch. TinyMCE is just overloaded with senseless stuff ...
@STEPHEN, There are some examples of WYMeditor in its svn repository, see http://files.wymeditor.org/wymeditor/trunk/src/examples/.
@OMTV, TinyMCE isn't hard to integrate, I agree. It's rather the amount of features which annoys me. Especially if I have multiple form fields in an admin form that would show a ton of buttons.
@PATRICKK: Oh yeah, the themes aren't that great. I've been starting to make things at least a bit better, with an own skin: http://django-page-cms.googlecode.com/svn/trunk/pages/media/pages/wymeditor/skins/django/
Using your code as a base, I came to more generalized widget, which can be used outside admin app - the difference is in updateSelector.
@ZGODA: Cool, would you mind sharing the changes with us?
here is my guide for wysiwyg administration on django using tinymce:
http://autoverse.net/index.php?f=2&id=53