TinyMCE with Django: “This field is required”

2020-07-27 16:32发布

问题:

I'm currently having issues using the TinyMCE editor within the Django admin interface. When entering text into two particular TinyMCE fields and pressing save, the form is returned with both fields empty, flagged red and tagged with a "This field is required" label:

This behaviour is odd, as I have implemented various TinyMCE editors within different models which have worked perfectly. I should clarify that I wish for both fields to be mandatory. The problem is that the text entered is being discarded, and the form is returned with both fields empty. Here is all of the relevant code:

companycms/news/models.py

from django.db import models
from tinymce import models  as tinymce_models

class Article(models.Model):
    headline = models.CharField(max_length=200)
    content = tinymce_models.HTMLField()
    about = tinymce_models.HTMLField()
    pub_date = models.DateTimeField('date published')
    url = models.CharField(max_length=200)

companycms/news/forms.py

from django import forms
from django.db.models import get_model
from django.contrib.auth.models import User
from companycms.widgets import AdvancedEditor
from news.models import Article
from django.db import models

class ArticleModelAdminForm(forms.ModelForm):
    headline = forms.CharField(max_length=200)
    content = forms.CharField(widget=AdvancedEditor())
    about = forms.CharField(widget=AdvancedEditor())
    pub_date = models.DateTimeField('date published')
    url = forms.CharField(max_length=200)

    class Meta:
         model = Article

companycms/news/admin.py

from django.contrib import admin
from news.models import Article
from news.forms import ArticleModelAdminForm

class ArticleAdmin(admin.ModelAdmin):
    list_display = ('headline', 'pub_date',)
    form = ArticleModelAdminForm

admin.site.register(Article, ArticleAdmin)

companycms/companycms/widgets.py

from django import forms
from django.conf import settings
from django.utils.safestring import mark_safe

class AdvancedEditor(forms.Textarea):
    class Media:
        js = ('/static/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,forecolor",
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_add:"forecolor,backcolor",


theme_advanced_font_sizes:"170%,10px,11px,12px,13px,14px,15px,16px,17px,18px,19px,20px,21px,22px,23px,24px,25px,26px,27px,28px,29px,30px,32px,48px",
            height: "350px",
            width: "653px"
        });
        </script>''')

Having checked the JavaScript console, there are no errors being returned, and I have checked other admin pages to find that this error doesn't appear anywhere else.

Thanks in advance for your help.

回答1:

I guess that your custom form and custom widget give you trouble. First two things. Just to be sure... Did you add tinymce in settings.py?

INSTALLED_APPS = (
    ...
    'tinymce',
)

And in urlpatterns?

urlpatterns = patterns('',
    ...
    (r'^tinymce/', include('tinymce.urls')),
)

According to the documentation all you need is the tinymce_models.HTMLField(). Like you did. All the rest of your code (custom form and custom widget) is not necessary to load TinyMCE. So in admin.py comment out:

#form = ArticleModelAdminForm

Now fingers crossed and test! Works right? You can switch it back on.

ArticleModelAdminForm needs only the fields that you want to adjust. Remove the headline, pub_date and url fields.

Don't add the js in a widget. But create a new js file. Delete the render function. Add the js location:

    class Media:
        js = ('/static/tiny_mce/tiny_mce.js', 
              '/static/tiny_mce/my_advanced_editor.js')

Move class Media to the ModelAdmin. Where it's loaded once, and not for each textarea.

Hope it helps!

EDIT:

TinyMCE looses data on submitting the form because it is initialized to many times. Django doesn't receive the POST data and correctly displays "This field is required". So make sure to initialize TinyMCE once:

models.py

class Article(models.Model):
    content = models.TextField() # Normal textfields (Don't load Tiny)
    about = models.TextField()

admin.py

class ArticleAdmin(admin.ModelAdmin):
    class Media:
        js = ('/static/tiny_mce/tiny_mce.js', 
              '/path/to/my_advanced_editor.js') # Add js to head of admin.

my_advanced_editor.js

   tinyMCE.init({
        mode: "textareas",  // This applies Tiny to all textareas.
        theme: "advanced",          
        ...
    });

Bonus: Django-TinyMCE makes it 'easy' to apply TinyMCE to fields but selecting fields with TinyMCE is also quite easy. With mode exact:

mode : "exact",
elements : "id_content,id_about",

Or deselect:

    mode: "textareas",  // All textareas except...
editor_deselector : "NoEditor" // deselects class="NoEditor"

In the last case your FormField needs a widget:

    widget=forms.TextInput(attrs={'class':'NoEditor'})


回答2:

You should add a blank=True parameter in companycms/news/models.py:

content = tinymce_models.HTMLField(blank=True)


回答3:

yes, in the Django settings.py comment out #'mode': 'textareas', and everything should be fine! ;)

TINYMCE_DEFAULT_CONFIG = {
    #'mode': "textareas",
    'theme': "advanced",
    'plugins': '''pagebreak, style, layer, table, save, advhr, advimage, advlink,
               emotions, iespell, inlinepopups, insertdatetime, preview, media, 
               searchreplace, print, contextmenu, paste, directionality, 
               fullscreen, noneditable, visualchars, nonbreaking, xhtmlxtras, 
               template, wordcount, advlist, autosave''',

    'theme_advanced_buttons1': '''bold, italic, underline, strikethrough, |,
                               justifyleft, justifycenter, justifyright,
                               justifyfull, fontselect, fontsizeselect,
                               fullscreen, code''',
    'theme_advanced_buttons2': '''bullist, numlist, |, outdent, indent,
                               blockquote, |, undo, redo, |, link, unlink, |,
                               forecolor, backcolor''',
    'theme_advanced_buttons3': '''tablecontrols, |, hr, sub, sup, |, charmap''',

    'theme_advanced_toolbar_location': "top",
    'theme_advanced_toolbar_align': "left",
    'theme_advanced_statusbar_location': "bottom",
    'theme_advanced_resizing': "true",

    'template_external_list_url': "lists/template_list.js",
    'external_link_list_url': "lists/link_list.js",
    'external_image_list_url': "lists/image_list.js",
    'media_external_list_url': "lists/media_list.js",

    'style_formats': [
      {'title': 'Bold text', 'inline': 'strong'},
      {'title': 'Red text', 'inline': 'span', 'styles': {'color' : '#ff0000'}},
      {'title': 'Help', 'inline': 'strong', 'classes': 'help'},
      {'title': 'Table styles'},
      {'title': 'Table row 1', 'selector': 'tr', 'classes': 'tablerow'}
    ],

    'width': '700',
    'height': '400'
}


回答4:

At the moment I had the same issue. My solution was:

delete line mode: "textareas",.

And now form saves after submit. :)