Support calling get_image_model and get_document_model at import time

Attempting to call get_image_model or get_document_model at the top level of a models.py file currently fails with "Models aren't loaded yet". This can be avoided by passing `require_ready=False` to apps.get_model.

This change makes it possible for third-party apps to define abstract models with foreign key references to the possibly-custom image or document model (which can then be subclassed into concrete models in the project itself - defining concrete models in the third-party app probably still isn't safe, as the model will end up being baked into the third-party app's migrations).
pull/7484/head
Matt Westcott 2020-11-20 15:20:13 +00:00 zatwierdzone przez LB Johnston
rodzic d43c203c29
commit 7f27e0abbc
7 zmienionych plików z 20 dodań i 4 usunięć

Wyświetl plik

@ -20,6 +20,7 @@ Changelog
* Add ability to return HTML in multiple image upload errors (Gordon Pendleton)
* Upgrade internal JS tooling; Node v14 plus other smaller package upgrades (LB (Ben Johnston))
* Add support for `non_field_errors` rendering in Workflow action modal (LB (Ben Johnston))
* Support calling `get_image_model` and `get_document_model` at import time (Matt Westcott)
* Fix: Delete button is now correct colour on snippets and modeladmin listings (Brandon Murch)
* Fix: Ensure that StreamBlock / ListBlock-level validation errors are counted towards error counts (Matt Westcott)
* Fix: InlinePanel add button is now keyboard navigatable (Jesse Menn)

Wyświetl plik

@ -31,6 +31,7 @@ Other features
* Add ability to return HTML in multiple image upload errors (Gordon Pendleton)
* Upgrade internal JS tooling; Node v14 plus other smaller package upgrades (LB (Ben Johnston))
* Add support for ``non_field_errors`` rendering in Workflow action modal (LB (Ben Johnston))
* Support calling ``get_image_model`` and ``get_document_model`` at import time (Matt Westcott)
Bug fixes
~~~~~~~~~

Wyświetl plik

@ -23,7 +23,7 @@ def get_document_model():
from django.apps import apps
model_string = get_document_model_string()
try:
return apps.get_model(model_string)
return apps.get_model(model_string, require_ready=False)
except ValueError:
raise ImproperlyConfigured("WAGTAILDOCS_DOCUMENT_MODEL must be of the form 'app_label.model_name'")
except LookupError:

Wyświetl plik

@ -9,7 +9,7 @@ from django.test.utils import override_settings
from wagtail.core.models import Collection, GroupCollectionPermission
from wagtail.documents import get_document_model, get_document_model_string, models, signal_handlers
from wagtail.images.tests.utils import get_test_image_file
from wagtail.tests.testapp.models import CustomDocument
from wagtail.tests.testapp.models import CustomDocument, ReimportedDocumentModel
from wagtail.tests.utils import WagtailTestUtils
@ -232,6 +232,9 @@ class TestGetDocumentModel(WagtailTestUtils, TestCase):
"""Test get_document_model with a custom document model"""
self.assertIs(get_document_model(), CustomDocument)
def test_get_document_model_at_import_time(self):
self.assertEqual(ReimportedDocumentModel, models.Document)
@override_settings(WAGTAILDOCS_DOCUMENT_MODEL='tests.CustomDocument')
def test_custom_get_document_model_string(self):
"""Test get_document_model_string with a custom document model"""

Wyświetl plik

@ -24,7 +24,7 @@ def get_image_model():
from django.apps import apps
model_string = get_image_model_string()
try:
return apps.get_model(model_string)
return apps.get_model(model_string, require_ready=False)
except ValueError:
raise ImproperlyConfigured("WAGTAILIMAGES_IMAGE_MODEL must be of the form 'app_label.model_name'")
except LookupError:

Wyświetl plik

@ -12,7 +12,7 @@ from willow.image import Image as WillowImage
from wagtail.core.models import Collection, GroupCollectionPermission, Page
from wagtail.images.models import Rendition, SourceImageIOError
from wagtail.images.rect import Rect
from wagtail.tests.testapp.models import EventPage, EventPageCarouselItem
from wagtail.tests.testapp.models import EventPage, EventPageCarouselItem, ReimportedImageModel
from wagtail.tests.utils import WagtailTestUtils
from .utils import Image, get_test_image_file
@ -26,6 +26,9 @@ class TestImage(TestCase):
file=get_test_image_file(colour='white'),
)
def test_get_image_model_at_import_time(self):
self.assertEqual(ReimportedImageModel, Image)
def test_is_portrait(self):
self.assertFalse(self.image.is_portrait())

Wyświetl plik

@ -35,8 +35,10 @@ from wagtail.core.blocks import (
CharBlock, FieldBlock, RawHTMLBlock, RichTextBlock, StreamBlock, StructBlock)
from wagtail.core.fields import RichTextField, StreamField
from wagtail.core.models import Orderable, Page, PageManager, PageQuerySet, Task, TranslatableMixin
from wagtail.documents import get_document_model
from wagtail.documents.edit_handlers import DocumentChooserPanel
from wagtail.documents.models import AbstractDocument, Document
from wagtail.images import get_image_model
from wagtail.images.blocks import ImageChooserBlock
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtail.images.models import AbstractImage, AbstractRendition, Image
@ -1571,3 +1573,9 @@ class DeadlyStreamPage(Page):
content_panels = Page.content_panels + [
StreamFieldPanel('body'),
]
# Check that get_image_model and get_document_model work at import time
# (so that it's possible to use them in foreign key definitions, for example)
ReimportedImageModel = get_image_model()
ReimportedDocumentModel = get_document_model()