Using the html editor in Django’s forms.py always results in has_changed() = True
.
I am using tinymce editor.
example
form django.forms import forms
from tinymce.widget import TinyMce
ex = '<p>asdf</p><p>\n</p><p>asdf</p>'
class a(forms.Form):
a = forms.Textarea(widget=TinyMce)
def clean_a(self):
retrun ex
def __init__(self, **kwargs):
super().__init__(initial={'a': ex})
If you use this example code, then calling changed_data always includes the a field.
The reason is that the bound field data of a is as follows.
print(f"{self['a']="})
"self['a']=<p>asdf</p><p>\r\n</p><p>asdf</p>"
It may be unclear what the difference is, but you can see that the text \n
to \r\n
has been added.
Ironically, although initial and cleaned_data match, it is recognized as a changed field because the data value of the bound field is different.
The process of confirming that data has been changed in the form appears to inherit multiple codes.
called on every field. Any ValidationError raised by this method will
not be associated with a particular field; it will have a special-case
association with the field named '__all__'.
"""
return self.cleaned_data
def has_changed(self):
"""Return True if data differs from initial."""
return bool(self.changed_data)
@cached_property
def changed_data(self):
return [name for name, bf in self._bound_items() if bf._has_changed()]
@property
def media(self):
"""Return all media required to render the widgets on this form."""
media = Media()
for field in self.fields.values():
media += field.widget.media
return media
is_valid = "Unknown"
else:
is_valid = self.is_bound and not self._errors
return "<%(cls)s bound=%(bound)s, valid=%(valid)s, fields=(%(fields)s)>" % {
"cls": self.__class__.__name__,
"bound": self.is_bound,
"valid": is_valid,
"fields": ";".join(self.fields),
}
def _bound_items(self):
"""Yield (name, bf) pairs, where bf is a BoundField object."""
for name in self.fields:
yield name, self[name]
def __iter__(self):
"""Yield the form's fields as BoundField objects."""
for name in self.fields:
yield self[name]
def __getitem__(self, name):
"""Return a string of HTML for representing this as a <textarea>."""
return self.as_widget(Textarea(), attrs, **kwargs)
def as_hidden(self, attrs=None, **kwargs):
"""
Return a string of HTML for representing this as an <input type="hidden">.
"""
return self.as_widget(self.field.hidden_widget(), attrs, **kwargs)
@property
def data(self):
"""
Return the data for this BoundField, or None if it wasn't given.
"""
return self.form._widget_data_value(self.field.widget, self.html_name)
def value(self):
"""
Return the value for this BoundField, using the initial value if
the form is not bound or the data otherwise.
"""
In the middle, self[name] is called, and after checking it, I found out that it was a boundfield.
import re
from django.core.exceptions import ValidationError
from django.forms.utils import RenderableFieldMixin, pretty_name
from django.forms.widgets import MultiWidget, Textarea, TextInput
from django.utils.functional import cached_property
from django.utils.html import format_html, html_safe
from django.utils.translation import gettext_lazy as _
__all__ = ("BoundField",)
class BoundField(RenderableFieldMixin):
"A Field plus data"
def __init__(self, form, field, name):
self.form = form
self.field = field
self.name = name
self.html_name = form.add_prefix(name)
This file has been truncated. show original
I wanna know.
How to change bound data or,
About how bound data is converted to HTML
or other solution.
If you create the field as a custom field subclass, you can edit the field in the to_python
method of that field. This would allow you to alter the contents of the field coming in, before it is compared with the existing data. (For example, you could strip all the ‘linefeed’ characters from the incoming data.)
See Form and field validation | Django documentation | Django for details.