Edytor WYSIWYG w adminie Django (newforms-admin)
Posted by Jacek Galanciak on May 14 2008
Pisząc systemy CMS, możemy się spotkać z powtarzającym się wymaganiem: ma być edytor WYSIWYG do tekstu. Widywałem aplikacje Django, w których główny admin był budowany na tym, co oferuje framework, a drugi - pisany ręcznie z edytorem WYSIWYG do większych tekstów. Zawsze jakieś rozwiązanie, ale da się lepiej. Jak?
Przede wszystkim: gałąź newforms-admin
Jeśli istnieje ktoś, kto jeszcze jej nie używa, niech zapozna się z jej opisem. W skrócie - bardziej elastyczny i podatny na własną rozbudowę admin budowany na bazie newforms.
Instalacja front-endu
Wybrałem FCKeditor, ze względu na duże możliwości i prostotę w implementacji, ale sposób działa dla dowolnie innego edytora. Należy ściągnąć paczkę i wrzucić ją tak, aby katalog z całością był dostępny pod ścieżką /fckeditor/. Tak jest domyślnie, ale nikt nam nie przeszkadza, by to zmienić, jeśli chcemy inaczej.
Drobna modyfikacja skryptu integrującego z Pythonem
Twórcy FCKeditora byli na tyle mili, by udostępniać go razem z pythonową klasą. Kopiujemy fckeditor.py do wybranego przez nas katalogu i przycinamy funkcje IsCompatible
do takiej postaci:
def IsCompatible(self):
return True
Widget dla newforms
from django.newforms.widgets import Widget
from django.utils.safestring import mark_safe
from django.utils.encoding import force_unicode
import myapp.core.fckeditor as fck
# ........
class FCKeditor(Widget):
def __init__ (self, attrs=None):
if attrs is not None:
self.attrs = attrs.copy()
else:
self.attrs = {}
self.__widget = fck.FCKeditor("FCKeditor1")
super(FCKeditor, self). __init__ (attrs)
self.setAtters(self.attrs)
def setAtters(self, attrs):
if attrs is None:
return
if 'basepath' in attrs:
self.__widget.BasePath = attrs['basepath']
if 'width' in attrs:
self.__widget.Width = attrs['width']
if 'height' in attrs:
self.__widget.Height = attrs['height']
if 'toolbar' in attrs:
self.__widget.ToolbarSet = attrs['toolbar']
def render(self, name, value, attrs=None):
if value is None: value = ''
value = force_unicode(value)
self.__widget.InstanceName = name
self.__widget.Value = value
self.setAtters(attrs)
final_attrs = self.build_attrs(attrs, name=name)
return mark_safe(self.__widget.CreateHtml())
Podczepienie widgetu do modelu
W moim przypadku jest to model Clip, zmieniam formularz dla textfield-u description:
class ClipOptions(admin.ModelAdmin):
# .........
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'description':
kwargs['widget'] = FCKeditor
return super(ClipOptions,self).formfield_for_dbfield(db_field,**kwargs)
# ...
global_admin = admin.AdminSite()
global_admin.register(Clip, ClipOptions)
Gotowe
Oto jak wygląda w realnej aplikacji: