Ver código fonte

Fix DocumentChooserBlock deconstruction for custom document models

Fixes #8989. The previous fix #9004 failed for custom document models because ChooserViewset assigns an internal name for the ChooserBlock class based on the model name, and if this is anything other than Document it won't match the name DocumentChooserBlock that it's exposed under in wagtail.documents.blocks. Fix this by replacing the `block_class` property with a `get_block_class` method that lets us specify the class name. As a bonus, user code that defines chooser blocks no longer has to directly hack the `__module__` attribute.
Matt Westcott 2 anos atrás
pai
commit
b4bc681865

+ 4 - 6
docs/extending/generic_views.md

@@ -90,16 +90,14 @@ from .views import person_chooser_viewset
 PersonChooserWidget = person_chooser_viewset.widget_class
 ```
 
-The viewset also makes a StreamField chooser block class available, as the property `block_class`. Placing the following code in `blocks.py` will make a chooser block available for use in StreamField definitions by importing `from myapp.blocks import PersonChooserBlock`:
+The viewset also makes a StreamField chooser block class available, through the method `get_block_class`. Placing the following code in `blocks.py` will make a chooser block available for use in StreamField definitions by importing `from myapp.blocks import PersonChooserBlock`:
 
 ```python
 from .views import person_chooser_viewset
 
-PersonChooserBlock = person_chooser_viewset.block_class
-
-# When deconstructing a PersonChooserBlock instance for migrations, the module path
-# used in migrations should point back to this module
-PersonChooserBlock.__module__ = "myapp.blocks"
+PersonChooserBlock = person_chooser_viewset.get_block_class(
+    name="PersonChooserBlock", module_path="myapp.blocks"
+)
 ```
 
 ## Chooser viewsets for non-model datasources

+ 1 - 1
docs/reference/viewsets.md

@@ -61,7 +61,7 @@ Viewsets are Wagtail's mechanism for defining a group of related admin views wit
    .. autoattribute:: widget_class
    .. autoattribute:: register_widget
    .. autoattribute:: base_block_class
-   .. autoattribute:: block_class
+   .. automethod:: get_block_class
    .. autoattribute:: creation_form_class
    .. autoattribute:: form_fields
    .. autoattribute:: exclude_form_fields

+ 10 - 4
wagtail/admin/viewsets/chooser.py

@@ -163,10 +163,13 @@ class ChooserViewSet(ViewSet):
             },
         )
 
-    @cached_property
-    def block_class(self):
+    def get_block_class(self, name=None, module_path=None):
         """
         Returns a StreamField ChooserBlock class using this chooser.
+
+        :param name: Name to give to the class; defaults to the model name with "ChooserBlock" appended
+        :param module_path: The dotted path of the module where the class can be imported from; used when
+            deconstructing the block definition for migration files.
         """
         meta = type(
             "Meta",
@@ -175,8 +178,8 @@ class ChooserViewSet(ViewSet):
                 "icon": self.icon,
             },
         )
-        return type(
-            "%sChooserBlock" % self.model_name,
+        cls = type(
+            name or "%sChooserBlock" % self.model_name,
             (self.base_block_class,),
             {
                 "target_model": self.model,
@@ -184,6 +187,9 @@ class ChooserViewSet(ViewSet):
                 "Meta": meta,
             },
         )
+        if module_path:
+            cls.__module__ = module_path
+        return cls
 
     def get_urlpatterns(self):
         return super().get_urlpatterns() + [

+ 3 - 5
wagtail/documents/blocks.py

@@ -1,7 +1,5 @@
 from wagtail.documents.views.chooser import viewset as chooser_viewset
 
-DocumentChooserBlock = chooser_viewset.block_class
-
-# When deconstructing a DocumentChooserBlock instance for migrations, the module path
-# used in migrations should point to this module
-DocumentChooserBlock.__module__ = "wagtail.documents.blocks"
+DocumentChooserBlock = chooser_viewset.get_block_class(
+    name="DocumentChooserBlock", module_path="wagtail.documents.blocks"
+)