wagtail 7.1.2__py3-none-any.whl → 7.2rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wagtail/__init__.py +1 -1
- wagtail/actions/copy_page.py +1 -1
- wagtail/actions/create_alias.py +1 -1
- wagtail/actions/delete_page.py +1 -1
- wagtail/actions/publish_page_revision.py +1 -1
- wagtail/actions/publish_revision.py +1 -1
- wagtail/actions/revert_to_page_revision.py +1 -1
- wagtail/actions/unpublish.py +1 -1
- wagtail/actions/unpublish_page.py +1 -1
- wagtail/admin/auth.py +3 -1
- wagtail/admin/checks.py +2 -2
- wagtail/admin/filters.py +28 -1
- wagtail/admin/forms/collections.py +1 -1
- wagtail/admin/forms/comments.py +1 -1
- wagtail/admin/forms/models.py +1 -1
- wagtail/admin/forms/pages.py +1 -1
- wagtail/admin/forms/tags.py +1 -1
- wagtail/admin/locale/cs/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/cs/LC_MESSAGES/django.po +25 -1
- wagtail/admin/locale/en/LC_MESSAGES/django.po +278 -192
- wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +29 -15
- wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/it/LC_MESSAGES/django.po +3 -2
- wagtail/admin/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/nl/LC_MESSAGES/django.po +57 -3
- wagtail/admin/locale/nl/LC_MESSAGES/djangojs.mo +0 -0
- wagtail/admin/locale/nl/LC_MESSAGES/djangojs.po +8 -2
- wagtail/admin/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/ru/LC_MESSAGES/django.po +58 -1
- wagtail/admin/locale/tr/LC_MESSAGES/django.mo +0 -0
- wagtail/admin/locale/tr/LC_MESSAGES/django.po +3 -2
- wagtail/admin/static/wagtailadmin/css/core.css +1 -1
- wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
- wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
- wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
- wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
- wagtail/admin/static/wagtailadmin/js/core.js +1 -1
- wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +2 -2
- wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
- wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
- wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
- wagtail/admin/static/wagtailadmin/js/icons.js +1 -1
- wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
- wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
- wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
- wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
- wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
- wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
- wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +2 -2
- wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-modal.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-transition.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery-3.6.0.min.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery-ui-1.13.2.min.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery.datetimepicker.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload-process.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/jquery.iframe-transport.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor/tag-it.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
- wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +1 -1
- wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
- wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
- wagtail/admin/templates/wagtailadmin/account/account.html +2 -0
- wagtail/admin/templates/wagtailadmin/base.html +14 -0
- wagtail/admin/templates/wagtailadmin/generic/chooser/chooser.html +2 -1
- wagtail/admin/templates/wagtailadmin/generic/chooser/creation_form.html +2 -1
- wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
- wagtail/admin/templates/wagtailadmin/panels/object_list.html +1 -1
- wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +3 -2
- wagtail/admin/templates/wagtailadmin/shared/formatted_field.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +19 -0
- wagtail/admin/templates/wagtailadmin/shared/panel.html +1 -1
- wagtail/admin/templates/wagtailadmin/shared/set_privacy.html +15 -0
- wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html +28 -1
- wagtail/admin/templates/wagtailadmin/shared/workflow_history/detail.html +2 -2
- wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_header.html → tables/ordering_header.html} +2 -2
- wagtail/admin/templates/wagtailadmin/tables/title_cell.html +1 -1
- wagtail/admin/templates/wagtailadmin/widgets/{daterange_input.html → range_input.html} +1 -1
- wagtail/admin/templates/wagtailadmin/workflows/task_chooser/chooser.html +4 -2
- wagtail/admin/templatetags/wagtailadmin_tags.py +41 -22
- wagtail/admin/tests/api/test_pages.py +7 -7
- wagtail/admin/tests/api/test_renderer_classes.py +16 -0
- wagtail/admin/tests/pages/test_create_page.py +34 -2
- wagtail/admin/tests/pages/test_edit_page.py +128 -14
- wagtail/admin/tests/pages/test_explorer_view.py +34 -7
- wagtail/admin/tests/pages/test_reorder_page.py +11 -0
- wagtail/admin/tests/test_collections_views.py +12 -0
- wagtail/admin/tests/test_edit_handlers.py +3 -3
- wagtail/admin/tests/test_filters.py +2 -2
- wagtail/admin/tests/test_keyboard_shortcuts.py +52 -2
- wagtail/admin/tests/test_menu.py +0 -2
- wagtail/admin/tests/test_privacy.py +16 -16
- wagtail/admin/tests/test_templatetags.py +137 -0
- wagtail/admin/tests/test_workflows.py +34 -0
- wagtail/admin/tests/viewsets/test_model_viewset.py +322 -0
- wagtail/admin/ui/tables/orderable.py +73 -0
- wagtail/admin/ui/tables/pages.py +3 -13
- wagtail/admin/views/collection_privacy.py +6 -2
- wagtail/admin/views/generic/__init__.py +1 -0
- wagtail/admin/views/generic/mixins.py +20 -2
- wagtail/admin/views/generic/models.py +67 -1
- wagtail/admin/views/generic/ordering.py +79 -0
- wagtail/admin/views/home.py +3 -3
- wagtail/admin/views/page_privacy.py +5 -2
- wagtail/admin/views/pages/create.py +1 -1
- wagtail/admin/views/pages/edit.py +2 -2
- wagtail/admin/views/pages/listing.py +7 -42
- wagtail/admin/views/pages/move.py +1 -1
- wagtail/admin/views/pages/ordering.py +1 -1
- wagtail/admin/viewsets/base.py +1 -1
- wagtail/admin/viewsets/model.py +49 -1
- wagtail/admin/wagtail_hooks.py +2 -1
- wagtail/admin/widgets/slug.py +10 -10
- wagtail/api/v2/serializers.py +1 -1
- wagtail/api/v2/tests/test_renderer_classes.py +32 -0
- wagtail/apps.py +2 -0
- wagtail/bin/wagtail.py +1 -1
- wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +14 -14
- wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.po +19 -2
- wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.po +18 -1
- wagtail/contrib/frontend_cache/tests.py +4 -2
- wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +4 -4
- wagtail/contrib/redirects/tests/test_tmp_storages.py +20 -0
- wagtail/contrib/redirects/tmp_storages.py +1 -1
- wagtail/contrib/redirects/views.py +3 -3
- wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +3 -3
- wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.po +43 -3
- wagtail/contrib/search_promotions/static/wagtailsearchpromotions/js/query-chooser-modal.js +1 -1
- wagtail/contrib/search_promotions/views/settings.py +2 -2
- wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.po +6 -1
- wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.po +6 -2
- wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.po +6 -1
- wagtail/contrib/settings/tests/site_specific/test_admin.py +40 -6
- wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/styleguide/templates/wagtailstyleguide/base.html +5 -5
- wagtail/contrib/table_block/blocks.py +1 -0
- wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +5 -1
- wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
- wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
- wagtail/coreutils.py +5 -5
- wagtail/documents/forms.py +18 -1
- wagtail/documents/locale/en/LC_MESSAGES/django.po +10 -10
- wagtail/documents/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/documents/locale/nl/LC_MESSAGES/django.po +9 -0
- wagtail/documents/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/documents/locale/ru/LC_MESSAGES/django.po +9 -0
- wagtail/documents/models.py +1 -1
- wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
- wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
- wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
- wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
- wagtail/documents/templates/wagtaildocs/documents/add.html +0 -34
- wagtail/documents/tests/test_admin_views.py +132 -26
- wagtail/documents/tests/test_collection_privacy.py +18 -4
- wagtail/documents/tests/test_form_overrides.py +1 -1
- wagtail/documents/tests/test_search.py +21 -8
- wagtail/documents/views/documents.py +1 -1
- wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/embeds/static/wagtailembeds/js/embed-chooser-modal.js +1 -1
- wagtail/images/forms.py +16 -1
- wagtail/images/locale/cs/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/cs/LC_MESSAGES/django.po +12 -1
- wagtail/images/locale/en/LC_MESSAGES/django.po +57 -46
- wagtail/images/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/nl/LC_MESSAGES/django.po +37 -14
- wagtail/images/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/images/locale/ru/LC_MESSAGES/django.po +20 -1
- wagtail/images/models.py +1 -1
- wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
- wagtail/images/static/wagtailimages/js/focal-point-chooser.js +1 -1
- wagtail/images/static/wagtailimages/js/image-block.js +1 -1
- wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
- wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
- wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
- wagtail/images/static/wagtailimages/js/image-url-generator.js +1 -1
- wagtail/images/static/wagtailimages/js/vendor/jquery.Jcrop.min.js +1 -1
- wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-image.js +1 -1
- wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-validate.js +1 -1
- wagtail/images/static/wagtailimages/js/vendor/load-image.min.js +1 -1
- wagtail/images/templates/wagtailimages/chooser/chooser.html +22 -13
- wagtail/images/templates/wagtailimages/chooser/image_preview_column_cell.html +10 -0
- wagtail/images/templates/wagtailimages/chooser/results.html +24 -20
- wagtail/images/templates/wagtailimages/chooser/title_column_cell.html +15 -0
- wagtail/images/templates/wagtailimages/images/add.html +0 -34
- wagtail/images/templates/wagtailimages/images/index.html +3 -3
- wagtail/images/templates/wagtailimages/images/index_results.html +1 -1
- wagtail/images/templates/wagtailimages/images/layout_toggle_button.html +8 -7
- wagtail/images/templatetags/wagtailimages_tags.py +2 -2
- wagtail/images/tests/test_admin_views.py +87 -0
- wagtail/images/tests/test_form_overrides.py +1 -1
- wagtail/images/tests/test_models.py +48 -9
- wagtail/images/views/chooser.py +66 -2
- wagtail/locale/en/LC_MESSAGES/django.po +55 -55
- wagtail/locale/is_IS/LC_MESSAGES/django.mo +0 -0
- wagtail/locale/is_IS/LC_MESSAGES/django.po +3 -3
- wagtail/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/locale/nl/LC_MESSAGES/django.po +11 -2
- wagtail/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/locale/ru/LC_MESSAGES/django.po +11 -1
- wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/locales/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/locales/locale/nl/LC_MESSAGES/django.po +12 -1
- wagtail/locales/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/locales/locale/ru/LC_MESSAGES/django.po +10 -1
- wagtail/locales/views.py +2 -2
- wagtail/models/orderable.py +10 -0
- wagtail/models/pages.py +9 -11
- wagtail/models/sites.py +1 -1
- wagtail/models/workflows.py +8 -5
- wagtail/project_template/home/tests.py +6 -7
- wagtail/project_template/project_name/settings/base.py +9 -9
- wagtail/project_template/requirements.txt +1 -1
- wagtail/query.py +7 -2
- wagtail/rich_text/rewriters.py +1 -1
- wagtail/search/apps.py +4 -49
- wagtail/search/backends/__init__.py +1 -113
- wagtail/search/backends/base.py +1 -547
- wagtail/search/backends/database/__init__.py +1 -50
- wagtail/search/backends/database/fallback.py +1 -253
- wagtail/search/backends/database/mysql/mysql.py +1 -700
- wagtail/search/backends/database/mysql/query.py +1 -258
- wagtail/search/backends/database/postgres/postgres.py +1 -749
- wagtail/search/backends/database/postgres/query.py +1 -83
- wagtail/search/backends/database/postgres/weights.py +1 -63
- wagtail/search/backends/database/sqlite/query.py +1 -294
- wagtail/search/backends/database/sqlite/sqlite.py +1 -719
- wagtail/search/backends/database/sqlite/utils.py +1 -35
- wagtail/search/backends/deprecation.py +45 -0
- wagtail/search/backends/elasticsearch7.py +18 -1260
- wagtail/search/backends/elasticsearch8.py +21 -96
- wagtail/search/backends/elasticsearch9.py +35 -0
- wagtail/search/backends/opensearch2.py +35 -0
- wagtail/search/backends/opensearch3.py +35 -0
- wagtail/search/index.py +1 -358
- wagtail/search/locale/en/LC_MESSAGES/django.po +2 -10
- wagtail/search/management/commands/update_index.py +1 -205
- wagtail/search/management/commands/wagtail_update_index.py +1 -4
- wagtail/search/models.py +32 -158
- wagtail/search/query.py +1 -114
- wagtail/search/queryset.py +1 -43
- wagtail/search/signal_handlers.py +1 -24
- wagtail/search/tasks.py +1 -10
- wagtail/search/tests/test_elasticsearch.py +22 -0
- wagtail/search/utils.py +1 -206
- wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
- wagtail/snippets/locale/en/LC_MESSAGES/django.po +3 -3
- wagtail/snippets/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/snippets/locale/ru/LC_MESSAGES/django.po +8 -1
- wagtail/snippets/locale/tr/LC_MESSAGES/django.mo +0 -0
- wagtail/snippets/locale/tr/LC_MESSAGES/django.po +8 -1
- wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
- wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
- wagtail/snippets/tests/test_reordering.py +319 -0
- wagtail/snippets/tests/test_snippets.py +65 -12
- wagtail/snippets/views/snippets.py +16 -0
- wagtail/test/numberformat.py +30 -0
- wagtail/test/settings.py +35 -12
- wagtail/test/testapp/fields.py +12 -0
- wagtail/test/testapp/migrations/0056_commentablejsonpage.py +50 -0
- wagtail/test/testapp/migrations/0057_featurecompletetoy_sort_order.py +23 -0
- wagtail/test/testapp/migrations/0058_customlocktask.py +31 -0
- wagtail/test/testapp/models.py +27 -0
- wagtail/test/testapp/views.py +3 -1
- wagtail/test/utils/page_tests.py +17 -17
- wagtail/test/utils/template_tests.py +4 -6
- wagtail/test/utils/wagtail_tests.py +1 -2
- wagtail/tests/test_page_model.py +15 -0
- wagtail/{search/tests → tests}/test_page_search.py +29 -2
- wagtail/tests/test_search_fields.py +69 -0
- wagtail/tests/test_tests.py +62 -6
- wagtail/tests/test_workflow.py +25 -1
- wagtail/users/locale/cs/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/cs/LC_MESSAGES/django.po +3 -0
- wagtail/users/locale/en/LC_MESSAGES/django.po +2 -2
- wagtail/users/locale/nl/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/nl/LC_MESSAGES/django.po +6 -3
- wagtail/users/locale/ru/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/ru/LC_MESSAGES/django.po +5 -1
- wagtail/users/locale/tr/LC_MESSAGES/django.mo +0 -0
- wagtail/users/locale/tr/LC_MESSAGES/django.po +78 -4
- wagtail/users/templates/wagtailusers/users/create.html +2 -0
- wagtail/users/templates/wagtailusers/users/edit.html +2 -0
- wagtail/users/tests/test_admin_views.py +4 -0
- wagtail/users/views/users.py +1 -1
- {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/METADATA +7 -6
- {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/RECORD +309 -315
- wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +0 -13
- wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +0 -13
- wagtail/search/tests/__init__.py +0 -0
- wagtail/search/tests/elasticsearch_common_tests.py +0 -251
- wagtail/search/tests/test_backends.py +0 -1215
- wagtail/search/tests/test_db_backend.py +0 -62
- wagtail/search/tests/test_elasticsearch7_backend.py +0 -1452
- wagtail/search/tests/test_elasticsearch8_backend.py +0 -15
- wagtail/search/tests/test_index_functions.py +0 -256
- wagtail/search/tests/test_indexed_class.py +0 -157
- wagtail/search/tests/test_mysql_backend.py +0 -192
- wagtail/search/tests/test_postgres_backend.py +0 -210
- wagtail/search/tests/test_queries.py +0 -332
- wagtail/search/tests/test_related_fields.py +0 -102
- wagtail/search/tests/test_sqlite_backend.py +0 -52
- wagtail/test/search/__init__.py +0 -0
- wagtail/test/search/apps.py +0 -9
- wagtail/test/search/fixtures/search.json +0 -545
- wagtail/test/search/migrations/0001_initial.py +0 -146
- wagtail/test/search/migrations/0002_bookunindexed.py +0 -43
- wagtail/test/search/migrations/0003_book_summary.py +0 -18
- wagtail/test/search/migrations/__init__.py +0 -0
- wagtail/test/search/models.py +0 -137
- /wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_cell.html → tables/ordering_cell.html} +0 -0
- /wagtail/{search/checks.py → checks.py} +0 -0
- {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/WHEEL +0 -0
- {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/entry_points.txt +0 -0
- {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/licenses/LICENSE +0 -0
- {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/top_level.txt +0 -0
wagtail/search/backends/base.py
CHANGED
|
@@ -1,547 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
from warnings import warn
|
|
3
|
-
|
|
4
|
-
from django.db.models import OrderBy
|
|
5
|
-
from django.db.models.functions.datetime import Extract as ExtractDate
|
|
6
|
-
from django.db.models.functions.datetime import ExtractYear
|
|
7
|
-
from django.db.models.lookups import Lookup
|
|
8
|
-
from django.db.models.query import QuerySet
|
|
9
|
-
from django.db.models.sql.where import NothingNode, WhereNode
|
|
10
|
-
|
|
11
|
-
from wagtail.search.index import class_is_indexed, get_indexed_models
|
|
12
|
-
from wagtail.search.query import MATCH_ALL, PlainText
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class FilterError(Exception):
|
|
16
|
-
pass
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class FieldError(Exception):
|
|
20
|
-
def __init__(self, *args, field_name=None, **kwargs):
|
|
21
|
-
self.field_name = field_name
|
|
22
|
-
super().__init__(*args, **kwargs)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class SearchFieldError(FieldError):
|
|
26
|
-
pass
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class FilterFieldError(FieldError):
|
|
30
|
-
pass
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
class OrderByFieldError(FieldError):
|
|
34
|
-
pass
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class BaseSearchQueryCompiler:
|
|
38
|
-
DEFAULT_OPERATOR = "or"
|
|
39
|
-
HANDLES_ORDER_BY_EXPRESSIONS = False
|
|
40
|
-
|
|
41
|
-
def __init__(
|
|
42
|
-
self,
|
|
43
|
-
queryset,
|
|
44
|
-
query,
|
|
45
|
-
fields=None,
|
|
46
|
-
operator=None,
|
|
47
|
-
order_by_relevance=True,
|
|
48
|
-
):
|
|
49
|
-
self.queryset = queryset
|
|
50
|
-
if query is None:
|
|
51
|
-
warn(
|
|
52
|
-
"Querying `None` is deprecated, use `MATCH_ALL` instead.",
|
|
53
|
-
DeprecationWarning,
|
|
54
|
-
)
|
|
55
|
-
query = MATCH_ALL
|
|
56
|
-
elif isinstance(query, str):
|
|
57
|
-
query = PlainText(query, operator=operator or self.DEFAULT_OPERATOR)
|
|
58
|
-
self.query = query
|
|
59
|
-
self.fields = fields
|
|
60
|
-
self.order_by_relevance = order_by_relevance
|
|
61
|
-
|
|
62
|
-
def _get_filterable_field(self, field_attname):
|
|
63
|
-
# Get field
|
|
64
|
-
field = {
|
|
65
|
-
field.get_attname(self.queryset.model): field
|
|
66
|
-
for field in self.queryset.model.get_filterable_search_fields()
|
|
67
|
-
}.get(field_attname, None)
|
|
68
|
-
|
|
69
|
-
return field
|
|
70
|
-
|
|
71
|
-
def _process_lookup(self, field, lookup, value):
|
|
72
|
-
raise NotImplementedError
|
|
73
|
-
|
|
74
|
-
def _process_match_none(self):
|
|
75
|
-
raise NotImplementedError
|
|
76
|
-
|
|
77
|
-
def _connect_filters(self, filters, connector, negated):
|
|
78
|
-
raise NotImplementedError
|
|
79
|
-
|
|
80
|
-
def _process_filter(self, field_attname, lookup, value, check_only=False):
|
|
81
|
-
# Get the field
|
|
82
|
-
field = self._get_filterable_field(field_attname)
|
|
83
|
-
|
|
84
|
-
if field is None:
|
|
85
|
-
raise FilterFieldError(
|
|
86
|
-
'Cannot filter search results with field "'
|
|
87
|
-
+ field_attname
|
|
88
|
-
+ "\". Please add index.FilterField('"
|
|
89
|
-
+ field_attname
|
|
90
|
-
+ "') to "
|
|
91
|
-
+ self.queryset.model.__name__
|
|
92
|
-
+ ".search_fields.",
|
|
93
|
-
field_name=field_attname,
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
# Process the lookup
|
|
97
|
-
if not check_only:
|
|
98
|
-
result = self._process_lookup(field, lookup, value)
|
|
99
|
-
|
|
100
|
-
if result is None:
|
|
101
|
-
raise FilterError(
|
|
102
|
-
'Could not apply filter on search results: "'
|
|
103
|
-
+ field_attname
|
|
104
|
-
+ "__"
|
|
105
|
-
+ lookup
|
|
106
|
-
+ " = "
|
|
107
|
-
+ str(value)
|
|
108
|
-
+ '". Lookup "'
|
|
109
|
-
+ lookup
|
|
110
|
-
+ '"" not recognised.'
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
return result
|
|
114
|
-
|
|
115
|
-
def _get_filters_from_where_node(self, where_node, check_only=False):
|
|
116
|
-
# Check if this is a leaf node
|
|
117
|
-
if isinstance(where_node, Lookup):
|
|
118
|
-
if isinstance(where_node.lhs, ExtractDate):
|
|
119
|
-
if not isinstance(where_node.lhs, ExtractYear):
|
|
120
|
-
raise FilterError(
|
|
121
|
-
'Cannot apply filter on search results: "'
|
|
122
|
-
+ where_node.lhs.lookup_name
|
|
123
|
-
+ '" queries are not supported.'
|
|
124
|
-
)
|
|
125
|
-
else:
|
|
126
|
-
field_attname = where_node.lhs.lhs.target.attname
|
|
127
|
-
lookup = where_node.lookup_name
|
|
128
|
-
if lookup == "gte":
|
|
129
|
-
# filter on year(date) >= value
|
|
130
|
-
# i.e. date >= Jan 1st of that year
|
|
131
|
-
value = datetime.date(int(where_node.rhs), 1, 1)
|
|
132
|
-
elif lookup == "gt":
|
|
133
|
-
# filter on year(date) > value
|
|
134
|
-
# i.e. date >= Jan 1st of the next year
|
|
135
|
-
value = datetime.date(int(where_node.rhs) + 1, 1, 1)
|
|
136
|
-
lookup = "gte"
|
|
137
|
-
elif lookup == "lte":
|
|
138
|
-
# filter on year(date) <= value
|
|
139
|
-
# i.e. date < Jan 1st of the next year
|
|
140
|
-
value = datetime.date(int(where_node.rhs) + 1, 1, 1)
|
|
141
|
-
lookup = "lt"
|
|
142
|
-
elif lookup == "lt":
|
|
143
|
-
# filter on year(date) < value
|
|
144
|
-
# i.e. date < Jan 1st of that year
|
|
145
|
-
value = datetime.date(int(where_node.rhs), 1, 1)
|
|
146
|
-
elif lookup == "exact":
|
|
147
|
-
# filter on year(date) == value
|
|
148
|
-
# i.e. date >= Jan 1st of that year and date < Jan 1st of the next year
|
|
149
|
-
filter1 = self._process_filter(
|
|
150
|
-
field_attname,
|
|
151
|
-
"gte",
|
|
152
|
-
datetime.date(int(where_node.rhs), 1, 1),
|
|
153
|
-
check_only=check_only,
|
|
154
|
-
)
|
|
155
|
-
filter2 = self._process_filter(
|
|
156
|
-
field_attname,
|
|
157
|
-
"lt",
|
|
158
|
-
datetime.date(int(where_node.rhs) + 1, 1, 1),
|
|
159
|
-
check_only=check_only,
|
|
160
|
-
)
|
|
161
|
-
if check_only:
|
|
162
|
-
return
|
|
163
|
-
else:
|
|
164
|
-
return self._connect_filters(
|
|
165
|
-
[filter1, filter2], "AND", False
|
|
166
|
-
)
|
|
167
|
-
else:
|
|
168
|
-
raise FilterError(
|
|
169
|
-
'Cannot apply filter on search results: "'
|
|
170
|
-
+ where_node.lhs.lookup_name
|
|
171
|
-
+ '" queries are not supported.'
|
|
172
|
-
)
|
|
173
|
-
else:
|
|
174
|
-
field_attname = where_node.lhs.target.attname
|
|
175
|
-
lookup = where_node.lookup_name
|
|
176
|
-
value = where_node.rhs
|
|
177
|
-
|
|
178
|
-
# Ignore pointer fields that show up in specific page type queries
|
|
179
|
-
if field_attname.endswith("_ptr_id"):
|
|
180
|
-
return
|
|
181
|
-
|
|
182
|
-
# Process the filter
|
|
183
|
-
return self._process_filter(
|
|
184
|
-
field_attname, lookup, value, check_only=check_only
|
|
185
|
-
)
|
|
186
|
-
|
|
187
|
-
elif isinstance(where_node, NothingNode):
|
|
188
|
-
return self._process_match_none()
|
|
189
|
-
|
|
190
|
-
elif isinstance(where_node, WhereNode):
|
|
191
|
-
# Get child filters
|
|
192
|
-
connector = where_node.connector
|
|
193
|
-
child_filters = [
|
|
194
|
-
self._get_filters_from_where_node(child)
|
|
195
|
-
for child in where_node.children
|
|
196
|
-
]
|
|
197
|
-
|
|
198
|
-
if not check_only:
|
|
199
|
-
child_filters = [
|
|
200
|
-
child_filter for child_filter in child_filters if child_filter
|
|
201
|
-
]
|
|
202
|
-
return self._connect_filters(
|
|
203
|
-
child_filters, connector, where_node.negated
|
|
204
|
-
)
|
|
205
|
-
|
|
206
|
-
else:
|
|
207
|
-
raise FilterError(
|
|
208
|
-
"Could not apply filter on search results: Unknown where node: "
|
|
209
|
-
+ str(type(where_node))
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
def _get_filters_from_queryset(self):
|
|
213
|
-
return self._get_filters_from_where_node(self.queryset.query.where)
|
|
214
|
-
|
|
215
|
-
def _get_order_by(self):
|
|
216
|
-
if self.order_by_relevance:
|
|
217
|
-
return
|
|
218
|
-
|
|
219
|
-
for field_name in self.queryset.query.order_by:
|
|
220
|
-
reverse = False
|
|
221
|
-
|
|
222
|
-
if isinstance(field_name, OrderBy):
|
|
223
|
-
if self.HANDLES_ORDER_BY_EXPRESSIONS:
|
|
224
|
-
continue
|
|
225
|
-
else:
|
|
226
|
-
raise OrderByFieldError(
|
|
227
|
-
f'Cannot sort search results with "{field_name}". '
|
|
228
|
-
"Please use a search backend that handles these "
|
|
229
|
-
"(e.g. database backend) or specify simple fields.",
|
|
230
|
-
field_name=field_name,
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
if field_name.startswith("-"):
|
|
234
|
-
reverse = True
|
|
235
|
-
field_name = field_name[1:]
|
|
236
|
-
|
|
237
|
-
field = self._get_filterable_field(field_name)
|
|
238
|
-
|
|
239
|
-
if field is None:
|
|
240
|
-
raise OrderByFieldError(
|
|
241
|
-
'Cannot sort search results with field "'
|
|
242
|
-
+ field_name
|
|
243
|
-
+ "\". Please add index.FilterField('"
|
|
244
|
-
+ field_name
|
|
245
|
-
+ "') to "
|
|
246
|
-
+ self.queryset.model.__name__
|
|
247
|
-
+ ".search_fields.",
|
|
248
|
-
field_name=field_name,
|
|
249
|
-
)
|
|
250
|
-
|
|
251
|
-
yield reverse, field
|
|
252
|
-
|
|
253
|
-
def check(self):
|
|
254
|
-
# Check search fields
|
|
255
|
-
if self.fields:
|
|
256
|
-
allowed_fields = {
|
|
257
|
-
field.field_name
|
|
258
|
-
for field in self.queryset.model.get_searchable_search_fields()
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
for field_name in self.fields:
|
|
262
|
-
if field_name not in allowed_fields:
|
|
263
|
-
raise SearchFieldError(
|
|
264
|
-
'Cannot search with field "'
|
|
265
|
-
+ field_name
|
|
266
|
-
+ "\". Please add index.SearchField('"
|
|
267
|
-
+ field_name
|
|
268
|
-
+ "') to "
|
|
269
|
-
+ self.queryset.model.__name__
|
|
270
|
-
+ ".search_fields.",
|
|
271
|
-
field_name=field_name,
|
|
272
|
-
)
|
|
273
|
-
|
|
274
|
-
# Check where clause
|
|
275
|
-
# Raises FilterFieldError if an unindexed field is being filtered on
|
|
276
|
-
self._get_filters_from_where_node(self.queryset.query.where, check_only=True)
|
|
277
|
-
|
|
278
|
-
# Check order by
|
|
279
|
-
# Raises OrderByFieldError if an unindexed field is being used to order by
|
|
280
|
-
list(self._get_order_by())
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
class BaseSearchResults:
|
|
284
|
-
supports_facet = False
|
|
285
|
-
|
|
286
|
-
def __init__(self, backend, query_compiler, prefetch_related=None):
|
|
287
|
-
self.backend = backend
|
|
288
|
-
self.query_compiler = query_compiler
|
|
289
|
-
self.prefetch_related = prefetch_related
|
|
290
|
-
self.start = 0
|
|
291
|
-
self.stop = None
|
|
292
|
-
self._results_cache = None
|
|
293
|
-
self._count_cache = None
|
|
294
|
-
self._score_field = None
|
|
295
|
-
# Attach the model to mimic a QuerySet so that we can inspect it after
|
|
296
|
-
# doing a search, e.g. to get the model's name in a paginator.
|
|
297
|
-
# The query_compiler may be None, e.g. when using EmptySearchResults.
|
|
298
|
-
self.model = query_compiler.queryset.model if query_compiler else None
|
|
299
|
-
|
|
300
|
-
def _set_limits(self, start=None, stop=None):
|
|
301
|
-
if stop is not None:
|
|
302
|
-
if self.stop is not None:
|
|
303
|
-
self.stop = min(self.stop, self.start + stop)
|
|
304
|
-
else:
|
|
305
|
-
self.stop = self.start + stop
|
|
306
|
-
|
|
307
|
-
if start is not None:
|
|
308
|
-
if self.stop is not None:
|
|
309
|
-
self.start = min(self.stop, self.start + start)
|
|
310
|
-
else:
|
|
311
|
-
self.start = self.start + start
|
|
312
|
-
|
|
313
|
-
def _clone(self):
|
|
314
|
-
klass = self.__class__
|
|
315
|
-
new = klass(
|
|
316
|
-
self.backend, self.query_compiler, prefetch_related=self.prefetch_related
|
|
317
|
-
)
|
|
318
|
-
new.start = self.start
|
|
319
|
-
new.stop = self.stop
|
|
320
|
-
new._score_field = self._score_field
|
|
321
|
-
return new
|
|
322
|
-
|
|
323
|
-
def _do_search(self):
|
|
324
|
-
raise NotImplementedError
|
|
325
|
-
|
|
326
|
-
def _do_count(self):
|
|
327
|
-
raise NotImplementedError
|
|
328
|
-
|
|
329
|
-
def results(self):
|
|
330
|
-
if self._results_cache is None:
|
|
331
|
-
self._results_cache = list(self._do_search())
|
|
332
|
-
return self._results_cache
|
|
333
|
-
|
|
334
|
-
def count(self):
|
|
335
|
-
if self._count_cache is None:
|
|
336
|
-
if self._results_cache is not None:
|
|
337
|
-
self._count_cache = len(self._results_cache)
|
|
338
|
-
else:
|
|
339
|
-
self._count_cache = self._do_count()
|
|
340
|
-
return self._count_cache
|
|
341
|
-
|
|
342
|
-
def __getitem__(self, key):
|
|
343
|
-
new = self._clone()
|
|
344
|
-
|
|
345
|
-
if isinstance(key, slice):
|
|
346
|
-
# Set limits
|
|
347
|
-
start = int(key.start) if key.start is not None else None
|
|
348
|
-
stop = int(key.stop) if key.stop is not None else None
|
|
349
|
-
new._set_limits(start, stop)
|
|
350
|
-
|
|
351
|
-
# Copy results cache
|
|
352
|
-
if self._results_cache is not None:
|
|
353
|
-
new._results_cache = self._results_cache[key]
|
|
354
|
-
|
|
355
|
-
return new
|
|
356
|
-
else:
|
|
357
|
-
if self._results_cache is not None:
|
|
358
|
-
return self._results_cache[key]
|
|
359
|
-
|
|
360
|
-
new.start = self.start + key
|
|
361
|
-
new.stop = self.start + key + 1
|
|
362
|
-
return list(new)[0]
|
|
363
|
-
|
|
364
|
-
def __iter__(self):
|
|
365
|
-
return iter(self.results())
|
|
366
|
-
|
|
367
|
-
def __len__(self):
|
|
368
|
-
return len(self.results())
|
|
369
|
-
|
|
370
|
-
def __repr__(self):
|
|
371
|
-
data = list(self[:21])
|
|
372
|
-
if len(data) > 20:
|
|
373
|
-
data[-1] = "...(remaining elements truncated)..."
|
|
374
|
-
return "<SearchResults %r>" % data
|
|
375
|
-
|
|
376
|
-
def annotate_score(self, field_name):
|
|
377
|
-
clone = self._clone()
|
|
378
|
-
clone._score_field = field_name
|
|
379
|
-
return clone
|
|
380
|
-
|
|
381
|
-
def facet(self, field_name):
|
|
382
|
-
raise NotImplementedError("This search backend does not support faceting")
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
class EmptySearchResults(BaseSearchResults):
|
|
386
|
-
def __init__(self):
|
|
387
|
-
super().__init__(None, None)
|
|
388
|
-
|
|
389
|
-
def _clone(self):
|
|
390
|
-
return self.__class__()
|
|
391
|
-
|
|
392
|
-
def _do_search(self):
|
|
393
|
-
return []
|
|
394
|
-
|
|
395
|
-
def _do_count(self):
|
|
396
|
-
return 0
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
class NullIndex:
|
|
400
|
-
"""
|
|
401
|
-
Index class that provides do-nothing implementations of the indexing operations required by
|
|
402
|
-
BaseSearchBackend. Use this for search backends that do not maintain an index, such as the
|
|
403
|
-
database backend.
|
|
404
|
-
"""
|
|
405
|
-
|
|
406
|
-
def add_model(self, model):
|
|
407
|
-
pass
|
|
408
|
-
|
|
409
|
-
def refresh(self):
|
|
410
|
-
pass
|
|
411
|
-
|
|
412
|
-
def add_item(self, item):
|
|
413
|
-
pass
|
|
414
|
-
|
|
415
|
-
def add_items(self, model, items):
|
|
416
|
-
pass
|
|
417
|
-
|
|
418
|
-
def delete_item(self, item):
|
|
419
|
-
pass
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
class BaseSearchBackend:
|
|
423
|
-
query_compiler_class = None
|
|
424
|
-
autocomplete_query_compiler_class = None
|
|
425
|
-
results_class = None
|
|
426
|
-
rebuilder_class = None
|
|
427
|
-
catch_indexing_errors = False
|
|
428
|
-
|
|
429
|
-
def __init__(self, params):
|
|
430
|
-
pass
|
|
431
|
-
|
|
432
|
-
def get_index_for_model(self, model):
|
|
433
|
-
return NullIndex()
|
|
434
|
-
|
|
435
|
-
def get_rebuilder(self):
|
|
436
|
-
return None
|
|
437
|
-
|
|
438
|
-
def reset_index(self):
|
|
439
|
-
raise NotImplementedError
|
|
440
|
-
|
|
441
|
-
def add_type(self, model):
|
|
442
|
-
self.get_index_for_model(model).add_model(model)
|
|
443
|
-
|
|
444
|
-
def refresh_index(self):
|
|
445
|
-
refreshed_indexes = []
|
|
446
|
-
for model in get_indexed_models():
|
|
447
|
-
index = self.get_index_for_model(model)
|
|
448
|
-
if index not in refreshed_indexes:
|
|
449
|
-
index.refresh()
|
|
450
|
-
refreshed_indexes.append(index)
|
|
451
|
-
|
|
452
|
-
def add(self, obj):
|
|
453
|
-
self.get_index_for_model(type(obj)).add_item(obj)
|
|
454
|
-
|
|
455
|
-
def add_bulk(self, model, obj_list):
|
|
456
|
-
self.get_index_for_model(model).add_items(model, obj_list)
|
|
457
|
-
|
|
458
|
-
def delete(self, obj):
|
|
459
|
-
self.get_index_for_model(type(obj)).delete_item(obj)
|
|
460
|
-
|
|
461
|
-
def _search(self, query_compiler_class, query, model_or_queryset, **kwargs):
|
|
462
|
-
# Find model/queryset
|
|
463
|
-
if isinstance(model_or_queryset, QuerySet):
|
|
464
|
-
model = model_or_queryset.model
|
|
465
|
-
queryset = model_or_queryset
|
|
466
|
-
else:
|
|
467
|
-
model = model_or_queryset
|
|
468
|
-
queryset = model_or_queryset.objects.all()
|
|
469
|
-
|
|
470
|
-
# Model must be a class that is in the index
|
|
471
|
-
if not class_is_indexed(model):
|
|
472
|
-
return EmptySearchResults()
|
|
473
|
-
|
|
474
|
-
# Check that there's still a query string after the clean up
|
|
475
|
-
if query == "":
|
|
476
|
-
return EmptySearchResults()
|
|
477
|
-
|
|
478
|
-
# Search
|
|
479
|
-
search_query_compiler = query_compiler_class(queryset, query, **kwargs)
|
|
480
|
-
|
|
481
|
-
# Check the query
|
|
482
|
-
search_query_compiler.check()
|
|
483
|
-
|
|
484
|
-
return self.results_class(self, search_query_compiler)
|
|
485
|
-
|
|
486
|
-
def search(
|
|
487
|
-
self,
|
|
488
|
-
query,
|
|
489
|
-
model_or_queryset,
|
|
490
|
-
fields=None,
|
|
491
|
-
operator=None,
|
|
492
|
-
order_by_relevance=True,
|
|
493
|
-
):
|
|
494
|
-
return self._search(
|
|
495
|
-
self.query_compiler_class,
|
|
496
|
-
query,
|
|
497
|
-
model_or_queryset,
|
|
498
|
-
fields=fields,
|
|
499
|
-
operator=operator,
|
|
500
|
-
order_by_relevance=order_by_relevance,
|
|
501
|
-
)
|
|
502
|
-
|
|
503
|
-
def autocomplete(
|
|
504
|
-
self,
|
|
505
|
-
query,
|
|
506
|
-
model_or_queryset,
|
|
507
|
-
fields=None,
|
|
508
|
-
operator=None,
|
|
509
|
-
order_by_relevance=True,
|
|
510
|
-
):
|
|
511
|
-
if self.autocomplete_query_compiler_class is None:
|
|
512
|
-
raise NotImplementedError(
|
|
513
|
-
"This search backend does not support the autocomplete API"
|
|
514
|
-
)
|
|
515
|
-
|
|
516
|
-
return self._search(
|
|
517
|
-
self.autocomplete_query_compiler_class,
|
|
518
|
-
query,
|
|
519
|
-
model_or_queryset,
|
|
520
|
-
fields=fields,
|
|
521
|
-
operator=operator,
|
|
522
|
-
order_by_relevance=order_by_relevance,
|
|
523
|
-
)
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
def get_model_root(model):
|
|
527
|
-
"""
|
|
528
|
-
This function finds the root model for any given model. The root model is
|
|
529
|
-
the highest concrete model that it descends from. If the model doesn't
|
|
530
|
-
descend from another concrete model then the model is it's own root model so
|
|
531
|
-
it is returned.
|
|
532
|
-
|
|
533
|
-
Examples:
|
|
534
|
-
>>> get_model_root(wagtailcore.Page)
|
|
535
|
-
wagtailcore.Page
|
|
536
|
-
|
|
537
|
-
>>> get_model_root(myapp.HomePage)
|
|
538
|
-
wagtailcore.Page
|
|
539
|
-
|
|
540
|
-
>>> get_model_root(wagtailimages.Image)
|
|
541
|
-
wagtailimages.Image
|
|
542
|
-
"""
|
|
543
|
-
if model._meta.parents:
|
|
544
|
-
parent_model = list(model._meta.parents.items())[0][0]
|
|
545
|
-
return get_model_root(parent_model)
|
|
546
|
-
|
|
547
|
-
return model
|
|
1
|
+
from wagtailmodelsearch.backends.base import * # noqa: F403
|
|
@@ -1,50 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
from django.db import connection
|
|
4
|
-
|
|
5
|
-
USE_SQLITE_FTS = None # True if sqlite FTS is available, False if not, None if untested
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def SearchBackend(params):
|
|
9
|
-
"""
|
|
10
|
-
Returns the appropriate search backend for the current 'default' database system
|
|
11
|
-
"""
|
|
12
|
-
if connection.vendor == "postgresql":
|
|
13
|
-
from .postgres.postgres import PostgresSearchBackend
|
|
14
|
-
|
|
15
|
-
return PostgresSearchBackend(params)
|
|
16
|
-
elif connection.vendor == "mysql":
|
|
17
|
-
from .mysql.mysql import MySQLSearchBackend
|
|
18
|
-
|
|
19
|
-
return MySQLSearchBackend(params)
|
|
20
|
-
elif connection.vendor == "sqlite":
|
|
21
|
-
global USE_SQLITE_FTS
|
|
22
|
-
|
|
23
|
-
if USE_SQLITE_FTS is None:
|
|
24
|
-
from .sqlite.utils import fts5_available, fts_table_exists
|
|
25
|
-
|
|
26
|
-
if not fts5_available():
|
|
27
|
-
USE_SQLITE_FTS = False
|
|
28
|
-
elif not fts_table_exists():
|
|
29
|
-
USE_SQLITE_FTS = False
|
|
30
|
-
warnings.warn(
|
|
31
|
-
"The installed SQLite library supports full-text search, but the table for storing "
|
|
32
|
-
"searchable content is missing. This probably means SQLite was upgraded after the "
|
|
33
|
-
"migration was applied. To enable full-text search, reapply wagtailsearch migration 0006 "
|
|
34
|
-
"or create the table manually."
|
|
35
|
-
)
|
|
36
|
-
else:
|
|
37
|
-
USE_SQLITE_FTS = True
|
|
38
|
-
|
|
39
|
-
if USE_SQLITE_FTS:
|
|
40
|
-
from .sqlite.sqlite import SQLiteSearchBackend
|
|
41
|
-
|
|
42
|
-
return SQLiteSearchBackend(params)
|
|
43
|
-
else:
|
|
44
|
-
from .fallback import DatabaseSearchBackend
|
|
45
|
-
|
|
46
|
-
return DatabaseSearchBackend(params)
|
|
47
|
-
else:
|
|
48
|
-
from .fallback import DatabaseSearchBackend
|
|
49
|
-
|
|
50
|
-
return DatabaseSearchBackend(params)
|
|
1
|
+
from wagtailmodelsearch.backends.database import * # noqa: F403
|