diff --git a/wagtail/admin/compare.py b/wagtail/admin/compare.py index 6f1f2d2357..bdc67de463 100644 --- a/wagtail/admin/compare.py +++ b/wagtail/admin/compare.py @@ -1,13 +1,18 @@ import difflib from bs4 import BeautifulSoup +from django.core.exceptions import ImproperlyConfigured +from django.db import models from django.utils.encoding import force_str from django.utils.html import escape, format_html, format_html_join from django.utils.safestring import mark_safe from django.utils.text import capfirst from django.utils.translation import gettext_lazy as _ +from taggit.managers import TaggableManager from wagtail.core import blocks +from wagtail.core.fields import RichTextField +from wagtail.utils.registry import ModelFieldRegistry def text_from_html(val): @@ -15,6 +20,32 @@ def text_from_html(val): return BeautifulSoup(force_str(val), "html5lib").getText() +comparison_class_registry = ModelFieldRegistry() + + +def register_comparison_class( + field_class, to=None, comparison_class=None, exact_class=False +): + """ + Define parameters for form fields to be used by WagtailAdminModelForm for a given + database field. + """ + + if comparison_class is None: + raise ImproperlyConfigured( + "register_comparison_class must be passed a 'comparison_class' keyword argument" + ) + + if to and field_class != models.ForeignKey: + raise ImproperlyConfigured( + "The 'to' argument on register_comparison_class is only valid for ForeignKey fields" + ) + + comparison_class_registry.register( + field_class, to=to, value=comparison_class, exact_class=exact_class + ) + + class FieldComparison: is_field = True is_child_relation = False @@ -56,6 +87,10 @@ class TextFieldComparison(FieldComparison): return diff_text(self.val_a, self.val_b).to_html() +register_comparison_class(models.CharField, comparison_class=TextFieldComparison) +register_comparison_class(models.TextField, comparison_class=TextFieldComparison) + + class RichTextFieldComparison(TextFieldComparison): def htmldiff(self): return diff_text( @@ -63,6 +98,9 @@ class RichTextFieldComparison(TextFieldComparison): ).to_html() +register_comparison_class(RichTextField, comparison_class=RichTextFieldComparison) + + def get_comparison_class_for_block(block): if hasattr(block, "get_comparison_class"): return block.get_comparison_class() @@ -346,6 +384,9 @@ class TagsFieldComparison(M2MFieldComparison): return tag.slug +register_comparison_class(TaggableManager, comparison_class=TagsFieldComparison) + + class ForeignObjectComparison(FieldComparison): def get_objects(self): model = self.field.related_model diff --git a/wagtail/admin/edit_handlers.py b/wagtail/admin/edit_handlers.py index db483f2df2..b88d49d1e2 100644 --- a/wagtail/admin/edit_handlers.py +++ b/wagtail/admin/edit_handlers.py @@ -7,7 +7,6 @@ from django.conf import settings from django.contrib.auth import get_user_model from django.core.exceptions import FieldDoesNotExist, ImproperlyConfigured from django.core.signals import setting_changed -from django.db.models.fields import CharField, TextField from django.dispatch import receiver from django.forms.formsets import DELETION_FIELD_NAME, ORDERING_FIELD_NAME from django.forms.models import fields_for_model @@ -16,12 +15,10 @@ from django.utils.functional import cached_property from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy from modelcluster.models import get_serializable_data_for_fields -from taggit.managers import TaggableManager from wagtail.admin import compare, widgets from wagtail.admin.forms.comments import CommentForm, CommentReplyForm from wagtail.admin.templatetags.wagtailadmin_tags import avatar_url, user_display_name -from wagtail.core.fields import RichTextField from wagtail.core.models import COMMENTS_RELATION_NAME, Page from wagtail.core.utils import camelcase_to_underscore from wagtail.utils.decorators import cached_classmethod @@ -550,20 +547,16 @@ class FieldPanel(EditHandler): if field.choices: return compare.ChoiceFieldComparison + comparison_class = compare.comparison_class_registry.get(field) + if comparison_class: + return comparison_class + if field.is_relation: - if isinstance(field, TaggableManager): - return compare.TagsFieldComparison - elif field.many_to_many: + if field.many_to_many: return compare.M2MFieldComparison return compare.ForeignObjectComparison - if isinstance(field, RichTextField): - return compare.RichTextFieldComparison - - if isinstance(field, (CharField, TextField)): - return compare.TextFieldComparison - except FieldDoesNotExist: pass