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.
pull/9007/head
Matt Westcott 2022-08-16 14:58:40 +01:00 zatwierdzone przez Matt Westcott
rodzic b740df734a
commit b4bc681865
4 zmienionych plików z 18 dodań i 16 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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() + [

Wyświetl plik

@ -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"
)