kopia lustrzana https://github.com/wagtail/wagtail
feat: Added `construct_image_chooser_queryset`, `construct_document_chooser_queryset` and `construct_page_chooser_queryset` hooks
rodzic
b00bf70229
commit
46c9cdda15
wagtail
wagtailadmin
tests
views
wagtaildocs
views
wagtailimages
tests
views
|
@ -7,6 +7,7 @@ Changelog
|
|||
* Use minified versions of jQuery and jQuery UI in the admin. Total savings without compression 371 KB (Tom Dyson)
|
||||
* Hooks can now specify the order in which they are run (Gagaro)
|
||||
* Added a `submit_buttons` block to login template (Gagaro)
|
||||
* Added `construct_image_chooser_queryset`, `construct_document_chooser_queryset` and `construct_page_chooser_queryset` hooks (Gagaro)
|
||||
* The homepage created in the project template is now titled "Home" rather than "Homepage" (Karl Hobley)
|
||||
* Signal receivers for custom `Image` and `Rendition` models are connected automatically (Mike Dingjan)
|
||||
* Fix: Marked 'Date from' / 'Date to' strings in wagtailforms for translation (Vorlif)
|
||||
|
|
|
@ -511,6 +511,66 @@ Hooks for customising the way users are directed through the process of creating
|
|||
return items.append( UserbarPuppyLinkItem() )
|
||||
|
||||
|
||||
Choosers
|
||||
--------
|
||||
|
||||
.. _construct_page_chooser_queryset:
|
||||
|
||||
``construct_page_chooser_queryset``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Called when rendering the page chooser view, to allow the page listing queryset to be customised. The callable passed into the hook will receive the current page queryset and the request object, and must return a Page queryset (either the original one, or a new one).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.wagtailcore import hooks
|
||||
|
||||
@hooks.register('construct_page_chooser_queryset')
|
||||
def show_my_pages_only(pages, request):
|
||||
# Only show own pages
|
||||
pages = pages.filter(owner=request.user)
|
||||
|
||||
return pages
|
||||
|
||||
|
||||
.. _construct_document_chooser_queryset:
|
||||
|
||||
``construct_document_chooser_queryset``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Called when rendering the document chooser view, to allow the document listing queryset to be customised. The callable passed into the hook will receive the current document queryset and the request object, and must return a Document queryset (either the original one, or a new one).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.wagtailcore import hooks
|
||||
|
||||
@hooks.register('construct_document_chooser_queryset')
|
||||
def show_my_uploaded_documents_only(documents, request):
|
||||
# Only show uploaded documents
|
||||
documents = documents.filter(uploaded_by=request.user)
|
||||
|
||||
return documents
|
||||
|
||||
|
||||
.. _construct_image_chooser_queryset:
|
||||
|
||||
``construct_image_chooser_queryset``
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Called when rendering the image chooser view, to allow the image listing queryset to be customised. The callable passed into the hook will receive the current image queryset and the request object, and must return a Document queryset (either the original one, or a new one).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from wagtail.wagtailcore import hooks
|
||||
|
||||
@hooks.register('construct_image_chooser_queryset')
|
||||
def show_my_uploaded_images_only(images, request):
|
||||
# Only show uploaded images
|
||||
images = images.filter(uploaded_by=request.user)
|
||||
|
||||
return images
|
||||
|
||||
|
||||
Page explorer
|
||||
-------------
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ Other features
|
|||
* Use minified versions of jQuery and jQuery UI in the admin. Total savings without compression 371 KB (Tom Dyson)
|
||||
* Hooks can now specify the order in which they are run (Gagaro)
|
||||
* Added a ``submit_buttons`` block to login template (Gagaro)
|
||||
* Added ``construct_image_chooser_queryset``, ``construct_document_chooser_queryset`` and ``construct_page_chooser_queryset`` hooks (Gagaro)
|
||||
* The homepage created in the project template is now titled "Home" rather than "Homepage" (Karl Hobley)
|
||||
* Signal receivers for custom ``Image`` and ``Rendition`` models are connected automatically (Mike Dingjan)
|
||||
|
||||
|
|
|
@ -27,6 +27,21 @@ class TestChooserBrowse(TestCase, WagtailTestUtils):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, 'wagtailadmin/chooser/browse.html')
|
||||
|
||||
def test_construct_queryset_hook(self):
|
||||
page = SimplePage(title="Test shown", content="hello")
|
||||
Page.get_first_root_node().add_child(instance=page)
|
||||
|
||||
page_not_shown = SimplePage(title="Test not shown", content="hello")
|
||||
Page.get_first_root_node().add_child(instance=page_not_shown)
|
||||
|
||||
def filter_pages(pages, request):
|
||||
return pages.filter(id=page.id)
|
||||
|
||||
with self.register_hook('construct_page_chooser_queryset', filter_pages):
|
||||
response = self.get()
|
||||
self.assertEqual(len(response.context['pages']), 1)
|
||||
self.assertEqual(response.context['pages'][0].specific, page)
|
||||
|
||||
|
||||
class TestCanChooseRootFlag(TestCase, WagtailTestUtils):
|
||||
def setUp(self):
|
||||
|
@ -297,6 +312,21 @@ class TestChooserSearch(TestCase, WagtailTestUtils):
|
|||
response = self.get({'page_type': 'foo'})
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_construct_queryset_hook(self):
|
||||
page = SimplePage(title="Test shown", content="hello")
|
||||
self.root_page.add_child(instance=page)
|
||||
|
||||
page_not_shown = SimplePage(title="Test not shown", content="hello")
|
||||
self.root_page.add_child(instance=page_not_shown)
|
||||
|
||||
def filter_pages(pages, request):
|
||||
return pages.filter(id=page.id)
|
||||
|
||||
with self.register_hook('construct_page_chooser_queryset', filter_pages):
|
||||
response = self.get({'q': 'Test'})
|
||||
self.assertEqual(len(response.context['pages']), 1)
|
||||
self.assertEqual(response.context['pages'][0].specific, page)
|
||||
|
||||
|
||||
class TestAutomaticRootPageDetection(TestCase, WagtailTestUtils):
|
||||
def setUp(self):
|
||||
|
|
|
@ -8,6 +8,7 @@ from django.shortcuts import get_object_or_404, render
|
|||
from wagtail.utils.pagination import paginate
|
||||
from wagtail.wagtailadmin.forms import EmailLinkChooserForm, ExternalLinkChooserForm, SearchForm
|
||||
from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
|
||||
from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailcore.models import Page
|
||||
from wagtail.wagtailcore.utils import resolve_model_string
|
||||
|
||||
|
@ -75,6 +76,10 @@ def browse(request, parent_page_id=None):
|
|||
# Get children of parent page
|
||||
pages = parent_page.get_children()
|
||||
|
||||
# allow hooks to modify the queryset
|
||||
for hook in hooks.get_hooks('construct_page_chooser_queryset'):
|
||||
pages = hook(pages, request)
|
||||
|
||||
# Filter them by page type
|
||||
if desired_classes != (Page,):
|
||||
# restrict the page listing to just those pages that:
|
||||
|
@ -131,15 +136,20 @@ def search(request, parent_page_id=None):
|
|||
except (ValueError, LookupError):
|
||||
raise Http404
|
||||
|
||||
pages = Page.objects.all()
|
||||
# allow hooks to modify the queryset
|
||||
for hook in hooks.get_hooks('construct_page_chooser_queryset'):
|
||||
pages = hook(pages, request)
|
||||
|
||||
search_form = SearchForm(request.GET)
|
||||
if search_form.is_valid() and search_form.cleaned_data['q']:
|
||||
pages = Page.objects.exclude(
|
||||
pages = pages.exclude(
|
||||
depth=1 # never include root
|
||||
)
|
||||
pages = filter_page_type(pages, desired_classes)
|
||||
pages = pages.search(search_form.cleaned_data['q'], fields=['title'])
|
||||
else:
|
||||
pages = Page.objects.none()
|
||||
pages = pages.none()
|
||||
|
||||
paginator, pages = paginate(request, pages, per_page=25)
|
||||
|
||||
|
|
|
@ -634,7 +634,7 @@ class TestMultipleDocumentUploader(TestCase, WagtailTestUtils):
|
|||
|
||||
class TestDocumentChooserView(TestCase, WagtailTestUtils):
|
||||
def setUp(self):
|
||||
self.login()
|
||||
self.user = self.login()
|
||||
|
||||
def test_simple(self):
|
||||
response = self.client.get(reverse('wagtaildocs:chooser'))
|
||||
|
@ -688,6 +688,44 @@ class TestDocumentChooserView(TestCase, WagtailTestUtils):
|
|||
# Check that we got the last page
|
||||
self.assertEqual(response.context['documents'].number, response.context['documents'].paginator.num_pages)
|
||||
|
||||
def test_construct_queryset_hook_browse(self):
|
||||
document = Document.objects.create(
|
||||
title="Test document shown",
|
||||
uploaded_by_user=self.user,
|
||||
)
|
||||
Document.objects.create(
|
||||
title="Test document not shown",
|
||||
)
|
||||
|
||||
def filter_documents(documents, request):
|
||||
# Filter on `uploaded_by_user` because it is
|
||||
# the only default FilterField in search_fields
|
||||
return documents.filter(uploaded_by_user=self.user)
|
||||
|
||||
with self.register_hook('construct_document_chooser_queryset', filter_documents):
|
||||
response = self.client.get(reverse('wagtaildocs:chooser'))
|
||||
self.assertEqual(len(response.context['documents']), 1)
|
||||
self.assertEqual(response.context['documents'][0], document)
|
||||
|
||||
def test_construct_queryset_hook_search(self):
|
||||
document = Document.objects.create(
|
||||
title="Test document shown",
|
||||
uploaded_by_user=self.user,
|
||||
)
|
||||
Document.objects.create(
|
||||
title="Test document not shown",
|
||||
)
|
||||
|
||||
def filter_documents(documents, request):
|
||||
# Filter on `uploaded_by_user` because it is
|
||||
# the only default FilterField in search_fields
|
||||
return documents.filter(uploaded_by_user=self.user)
|
||||
|
||||
with self.register_hook('construct_document_chooser_queryset', filter_documents):
|
||||
response = self.client.get(reverse('wagtaildocs:chooser'), {'q': 'Test'})
|
||||
self.assertEqual(len(response.context['documents']), 1)
|
||||
self.assertEqual(response.context['documents'][0], document)
|
||||
|
||||
|
||||
class TestDocumentChooserChosenView(TestCase, WagtailTestUtils):
|
||||
def setUp(self):
|
||||
|
|
|
@ -9,6 +9,7 @@ from wagtail.utils.pagination import paginate
|
|||
from wagtail.wagtailadmin.forms import SearchForm
|
||||
from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
|
||||
from wagtail.wagtailadmin.utils import PermissionPolicyChecker
|
||||
from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailcore.models import Collection
|
||||
from wagtail.wagtaildocs.forms import get_document_form
|
||||
from wagtail.wagtaildocs.models import get_document_model
|
||||
|
@ -41,12 +42,14 @@ def chooser(request):
|
|||
else:
|
||||
uploadform = None
|
||||
|
||||
documents = []
|
||||
documents = Document.objects.all()
|
||||
|
||||
# allow hooks to modify the queryset
|
||||
for hook in hooks.get_hooks('construct_document_chooser_queryset'):
|
||||
documents = hook(documents, request)
|
||||
|
||||
q = None
|
||||
is_searching = False
|
||||
if 'q' in request.GET or 'p' in request.GET or 'collection_id' in request.GET:
|
||||
documents = Document.objects.all()
|
||||
|
||||
collection_id = request.GET.get('collection_id')
|
||||
if collection_id:
|
||||
|
@ -77,16 +80,16 @@ def chooser(request):
|
|||
if len(collections) < 2:
|
||||
collections = None
|
||||
|
||||
documents = Document.objects.order_by('-created_at')
|
||||
documents = documents.order_by('-created_at')
|
||||
paginator, documents = paginate(request, documents, per_page=10)
|
||||
|
||||
return render_modal_workflow(request, 'wagtaildocs/chooser/chooser.html', 'wagtaildocs/chooser/chooser.js', {
|
||||
'documents': documents,
|
||||
'uploadform': uploadform,
|
||||
'searchform': searchform,
|
||||
'collections': collections,
|
||||
'is_searching': False,
|
||||
})
|
||||
return render_modal_workflow(request, 'wagtaildocs/chooser/chooser.html', 'wagtaildocs/chooser/chooser.js', {
|
||||
'documents': documents,
|
||||
'uploadform': uploadform,
|
||||
'searchform': searchform,
|
||||
'collections': collections,
|
||||
'is_searching': False,
|
||||
})
|
||||
|
||||
|
||||
def document_chosen(request, document_id):
|
||||
|
|
|
@ -412,7 +412,7 @@ class TestImageDeleteView(TestCase, WagtailTestUtils):
|
|||
|
||||
class TestImageChooserView(TestCase, WagtailTestUtils):
|
||||
def setUp(self):
|
||||
self.login()
|
||||
self.user = self.login()
|
||||
|
||||
def get(self, params={}):
|
||||
return self.client.get(reverse('wagtailimages:chooser'), params)
|
||||
|
@ -452,6 +452,48 @@ class TestImageChooserView(TestCase, WagtailTestUtils):
|
|||
# Results should not include images that just have 'even' in the title
|
||||
self.assertNotContains(response, "Test image 3 is even better")
|
||||
|
||||
def test_construct_queryset_hook_browse(self):
|
||||
image = Image.objects.create(
|
||||
title="Test image shown",
|
||||
file=get_test_image_file(),
|
||||
uploaded_by_user=self.user,
|
||||
)
|
||||
Image.objects.create(
|
||||
title="Test image not shown",
|
||||
file=get_test_image_file(),
|
||||
)
|
||||
|
||||
def filter_images(images, request):
|
||||
# Filter on `uploaded_by_user` because it is
|
||||
# the only default FilterField in search_fields
|
||||
return images.filter(uploaded_by_user=self.user)
|
||||
|
||||
with self.register_hook('construct_image_chooser_queryset', filter_images):
|
||||
response = self.get()
|
||||
self.assertEqual(len(response.context['images']), 1)
|
||||
self.assertEqual(response.context['images'][0], image)
|
||||
|
||||
def test_construct_queryset_hook_search(self):
|
||||
image = Image.objects.create(
|
||||
title="Test image shown",
|
||||
file=get_test_image_file(),
|
||||
uploaded_by_user=self.user,
|
||||
)
|
||||
Image.objects.create(
|
||||
title="Test image not shown",
|
||||
file=get_test_image_file(),
|
||||
)
|
||||
|
||||
def filter_images(images, request):
|
||||
# Filter on `uploaded_by_user` because it is
|
||||
# the only default FilterField in search_fields
|
||||
return images.filter(uploaded_by_user=self.user)
|
||||
|
||||
with self.register_hook('construct_image_chooser_queryset', filter_images):
|
||||
response = self.get({'q': 'Test'})
|
||||
self.assertEqual(len(response.context['images']), 1)
|
||||
self.assertEqual(response.context['images'][0], image)
|
||||
|
||||
|
||||
class TestImageChooserChosenView(TestCase, WagtailTestUtils):
|
||||
def setUp(self):
|
||||
|
|
|
@ -9,6 +9,7 @@ from wagtail.utils.pagination import paginate
|
|||
from wagtail.wagtailadmin.forms import SearchForm
|
||||
from wagtail.wagtailadmin.modal_workflow import render_modal_workflow
|
||||
from wagtail.wagtailadmin.utils import PermissionPolicyChecker, popular_tags_for_model
|
||||
from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailcore.models import Collection
|
||||
from wagtail.wagtailimages import get_image_model
|
||||
from wagtail.wagtailimages.formats import get_image_format
|
||||
|
@ -49,6 +50,10 @@ def chooser(request):
|
|||
|
||||
images = Image.objects.order_by('-created_at')
|
||||
|
||||
# allow hooks to modify the queryset
|
||||
for hook in hooks.get_hooks('construct_image_chooser_queryset'):
|
||||
images = hook(images, request)
|
||||
|
||||
q = None
|
||||
if (
|
||||
'q' in request.GET or 'p' in request.GET or 'tag' in request.GET or
|
||||
|
@ -91,16 +96,16 @@ def chooser(request):
|
|||
|
||||
paginator, images = paginate(request, images, per_page=12)
|
||||
|
||||
return render_modal_workflow(request, 'wagtailimages/chooser/chooser.html', 'wagtailimages/chooser/chooser.js', {
|
||||
'images': images,
|
||||
'uploadform': uploadform,
|
||||
'searchform': searchform,
|
||||
'is_searching': False,
|
||||
'query_string': q,
|
||||
'will_select_format': request.GET.get('select_format'),
|
||||
'popular_tags': popular_tags_for_model(Image),
|
||||
'collections': collections,
|
||||
})
|
||||
return render_modal_workflow(request, 'wagtailimages/chooser/chooser.html', 'wagtailimages/chooser/chooser.js', {
|
||||
'images': images,
|
||||
'uploadform': uploadform,
|
||||
'searchform': searchform,
|
||||
'is_searching': False,
|
||||
'query_string': q,
|
||||
'will_select_format': request.GET.get('select_format'),
|
||||
'popular_tags': popular_tags_for_model(Image),
|
||||
'collections': collections,
|
||||
})
|
||||
|
||||
|
||||
def image_chosen(request, image_id):
|
||||
|
|
Ładowanie…
Reference in New Issue