Make document upload forms use the correct widget for custom tag models

pull/8592/head
Matt Westcott 2022-01-27 16:15:13 +00:00 zatwierdzone przez LB (Ben Johnston)
rodzic 46efee9eeb
commit f57fc32ed0
4 zmienionych plików z 178 dodań i 4 usunięć

Wyświetl plik

@ -3,12 +3,12 @@ from django.conf import settings
from django.forms.models import modelform_factory
from django.utils.translation import gettext_lazy as _
from wagtail.admin import widgets
from wagtail.admin.forms.collections import (
BaseCollectionMemberForm,
CollectionChoiceField,
collection_member_permission_formset_factory,
)
from wagtail.admin.widgets import AdminTagWidget
from wagtail.documents.models import Document
from wagtail.documents.permissions import (
permission_policy as documents_permission_policy,
@ -34,7 +34,7 @@ class BaseDocumentForm(BaseCollectionMemberForm):
permission_policy = documents_permission_policy
class Meta:
widgets = {"tags": widgets.AdminTagWidget, "file": forms.FileInput()}
widgets = {"tags": AdminTagWidget, "file": forms.FileInput()}
def get_document_base_form():
@ -57,10 +57,23 @@ def get_document_form(model):
# and when only one collection exists, it will get hidden anyway.
fields = list(fields) + ["collection"]
BaseForm = get_document_base_form()
# If the base form specifies the 'tags' widget as a plain unconfigured AdminTagWidget,
# substitute one that correctly passes the tag model used on the document model.
# (If the widget has been overridden via WAGTAILDOCS_DOCUMENT_FORM_BASE, leave it
# alone and trust that they know what they're doing)
widgets = None
if BaseForm._meta.widgets.get("tags") == AdminTagWidget:
tag_model = model._meta.get_field("tags").related_model
widgets = BaseForm._meta.widgets.copy()
widgets["tags"] = AdminTagWidget(tag_model=tag_model)
return modelform_factory(
model,
form=get_document_base_form(),
form=BaseForm,
fields=fields,
widgets=widgets,
formfield_callback=formfield_for_dbfield,
)
@ -73,10 +86,23 @@ def get_document_multi_form(model):
if "collection" not in fields:
fields.append("collection")
BaseForm = get_document_base_form()
# If the base form specifies the 'tags' widget as a plain unconfigured AdminTagWidget,
# substitute one that correctly passes the tag model used on the document model.
# (If the widget has been overridden via WAGTAILDOCS_DOCUMENT_FORM_BASE, leave it
# alone and trust that they know what they're doing)
widgets = None
if BaseForm._meta.widgets.get("tags") == AdminTagWidget:
tag_model = model._meta.get_field("tags").related_model
widgets = BaseForm._meta.widgets.copy()
widgets["tags"] = AdminTagWidget(tag_model=tag_model)
return modelform_factory(
model,
form=get_document_base_form(),
form=BaseForm,
fields=fields,
widgets=widgets,
formfield_callback=formfield_for_dbfield,
)

Wyświetl plik

@ -1,5 +1,6 @@
from django import forms
from django.test import TestCase, override_settings
from taggit import models as taggit_models
from wagtail.admin import widgets
from wagtail.admin.widgets import AdminDateTimeInput
@ -11,6 +12,7 @@ from wagtail.documents.forms import (
get_document_multi_form,
)
from wagtail.test.testapp.media_forms import AlternateDocumentForm, OverriddenWidget
from wagtail.test.testapp.models import CustomRestaurantDocument, RestaurantTag
class TestDocumentFormOverride(TestCase):
@ -26,8 +28,15 @@ class TestDocumentFormOverride(TestCase):
form_cls = get_document_form(models.Document)
form = form_cls()
self.assertIsInstance(form.fields["tags"].widget, widgets.AdminTagWidget)
self.assertEqual(form.fields["tags"].widget.tag_model, taggit_models.Tag)
self.assertIsInstance(form.fields["file"].widget, forms.FileInput)
def test_tags_widget_with_custom_tag_model(self):
form_cls = get_document_form(CustomRestaurantDocument)
form = form_cls()
self.assertIsInstance(form.fields["tags"].widget, widgets.AdminTagWidget)
self.assertEqual(form.fields["tags"].widget.tag_model, RestaurantTag)
@override_settings(
WAGTAILDOCS_DOCUMENT_FORM_BASE="wagtail.test.testapp.media_forms.AlternateDocumentForm"
)

Wyświetl plik

@ -0,0 +1,117 @@
# Generated by Django 3.2.11 on 2022-01-27 15:00
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import taggit.managers
import wagtail.core.models.collections
import wagtail.search.index
class Migration(migrations.Migration):
dependencies = [
("wagtailcore", "0066_collection_management_permissions"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("tests", "0063_jsonblockcountsstreammodel_and_more"),
]
operations = [
migrations.CreateModel(
name="CustomRestaurantDocument",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("title", models.CharField(max_length=255, verbose_name="title")),
("file", models.FileField(upload_to="documents", verbose_name="file")),
(
"created_at",
models.DateTimeField(auto_now_add=True, verbose_name="created at"),
),
("file_size", models.PositiveIntegerField(editable=False, null=True)),
(
"file_hash",
models.CharField(blank=True, editable=False, max_length=40),
),
(
"collection",
models.ForeignKey(
default=wagtail.core.models.collections.get_root_collection_id,
on_delete=django.db.models.deletion.CASCADE,
related_name="+",
to="wagtailcore.collection",
verbose_name="collection",
),
),
],
options={
"verbose_name": "document",
"verbose_name_plural": "documents",
"abstract": False,
},
bases=(wagtail.search.index.Indexed, models.Model),
),
migrations.CreateModel(
name="TaggedRestaurantDocument",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"content_object",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="tagged_items",
to="tests.customrestaurantdocument",
),
),
(
"tag",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="tagged_documents",
to="tests.restauranttag",
),
),
],
options={
"abstract": False,
},
),
migrations.AddField(
model_name="customrestaurantdocument",
name="tags",
field=taggit.managers.TaggableManager(
blank=True,
help_text=None,
through="tests.TaggedRestaurantDocument",
to="tests.RestaurantTag",
verbose_name="tags",
),
),
migrations.AddField(
model_name="customrestaurantdocument",
name="uploaded_by_user",
field=models.ForeignKey(
blank=True,
editable=False,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to=settings.AUTH_USER_MODEL,
verbose_name="uploaded by user",
),
),
]

Wyświetl plik

@ -1712,3 +1712,25 @@ class DeadlyStreamPage(Page):
# (so that it's possible to use them in foreign key definitions, for example)
ReimportedImageModel = get_image_model()
ReimportedDocumentModel = get_document_model()
# Custom document model with a custom tag field
class TaggedRestaurantDocument(ItemBase):
tag = models.ForeignKey(
RestaurantTag, related_name="tagged_documents", on_delete=models.CASCADE
)
content_object = models.ForeignKey(
to="tests.CustomRestaurantDocument",
on_delete=models.CASCADE,
related_name="tagged_items",
)
class CustomRestaurantDocument(AbstractDocument):
tags = TaggableManager(
help_text=None,
blank=True,
verbose_name="tags",
through=TaggedRestaurantDocument,
)
admin_form_fields = Document.admin_form_fields