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.
Files changed (332) hide show
  1. wagtail/__init__.py +1 -1
  2. wagtail/actions/copy_page.py +1 -1
  3. wagtail/actions/create_alias.py +1 -1
  4. wagtail/actions/delete_page.py +1 -1
  5. wagtail/actions/publish_page_revision.py +1 -1
  6. wagtail/actions/publish_revision.py +1 -1
  7. wagtail/actions/revert_to_page_revision.py +1 -1
  8. wagtail/actions/unpublish.py +1 -1
  9. wagtail/actions/unpublish_page.py +1 -1
  10. wagtail/admin/auth.py +3 -1
  11. wagtail/admin/checks.py +2 -2
  12. wagtail/admin/filters.py +28 -1
  13. wagtail/admin/forms/collections.py +1 -1
  14. wagtail/admin/forms/comments.py +1 -1
  15. wagtail/admin/forms/models.py +1 -1
  16. wagtail/admin/forms/pages.py +1 -1
  17. wagtail/admin/forms/tags.py +1 -1
  18. wagtail/admin/locale/cs/LC_MESSAGES/django.mo +0 -0
  19. wagtail/admin/locale/cs/LC_MESSAGES/django.po +25 -1
  20. wagtail/admin/locale/en/LC_MESSAGES/django.po +278 -192
  21. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +29 -15
  22. wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
  23. wagtail/admin/locale/it/LC_MESSAGES/django.po +3 -2
  24. wagtail/admin/locale/nl/LC_MESSAGES/django.mo +0 -0
  25. wagtail/admin/locale/nl/LC_MESSAGES/django.po +57 -3
  26. wagtail/admin/locale/nl/LC_MESSAGES/djangojs.mo +0 -0
  27. wagtail/admin/locale/nl/LC_MESSAGES/djangojs.po +8 -2
  28. wagtail/admin/locale/ru/LC_MESSAGES/django.mo +0 -0
  29. wagtail/admin/locale/ru/LC_MESSAGES/django.po +58 -1
  30. wagtail/admin/locale/tr/LC_MESSAGES/django.mo +0 -0
  31. wagtail/admin/locale/tr/LC_MESSAGES/django.po +3 -2
  32. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  33. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  34. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  35. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  36. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  37. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  38. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  39. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +2 -2
  40. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  41. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  42. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  43. wagtail/admin/static/wagtailadmin/js/icons.js +1 -1
  44. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  45. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  46. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  47. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  48. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  49. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  50. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  51. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  52. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  53. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  54. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  55. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  56. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +2 -2
  57. wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-modal.js +1 -1
  58. wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-transition.js +1 -1
  59. wagtail/admin/static/wagtailadmin/js/vendor/jquery-3.6.0.min.js +1 -1
  60. wagtail/admin/static/wagtailadmin/js/vendor/jquery-ui-1.13.2.min.js +1 -1
  61. wagtail/admin/static/wagtailadmin/js/vendor/jquery.datetimepicker.js +1 -1
  62. wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload-process.js +1 -1
  63. wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload.js +1 -1
  64. wagtail/admin/static/wagtailadmin/js/vendor/jquery.iframe-transport.js +1 -1
  65. wagtail/admin/static/wagtailadmin/js/vendor/tag-it.js +1 -1
  66. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  67. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +1 -1
  68. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  69. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  70. wagtail/admin/templates/wagtailadmin/account/account.html +2 -0
  71. wagtail/admin/templates/wagtailadmin/base.html +14 -0
  72. wagtail/admin/templates/wagtailadmin/generic/chooser/chooser.html +2 -1
  73. wagtail/admin/templates/wagtailadmin/generic/chooser/creation_form.html +2 -1
  74. wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
  75. wagtail/admin/templates/wagtailadmin/panels/object_list.html +1 -1
  76. wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +3 -2
  77. wagtail/admin/templates/wagtailadmin/shared/formatted_field.html +1 -1
  78. wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
  79. wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +19 -0
  80. wagtail/admin/templates/wagtailadmin/shared/panel.html +1 -1
  81. wagtail/admin/templates/wagtailadmin/shared/set_privacy.html +15 -0
  82. wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html +28 -1
  83. wagtail/admin/templates/wagtailadmin/shared/workflow_history/detail.html +2 -2
  84. wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_header.html → tables/ordering_header.html} +2 -2
  85. wagtail/admin/templates/wagtailadmin/tables/title_cell.html +1 -1
  86. wagtail/admin/templates/wagtailadmin/widgets/{daterange_input.html → range_input.html} +1 -1
  87. wagtail/admin/templates/wagtailadmin/workflows/task_chooser/chooser.html +4 -2
  88. wagtail/admin/templatetags/wagtailadmin_tags.py +41 -22
  89. wagtail/admin/tests/api/test_pages.py +7 -7
  90. wagtail/admin/tests/api/test_renderer_classes.py +16 -0
  91. wagtail/admin/tests/pages/test_create_page.py +34 -2
  92. wagtail/admin/tests/pages/test_edit_page.py +128 -14
  93. wagtail/admin/tests/pages/test_explorer_view.py +34 -7
  94. wagtail/admin/tests/pages/test_reorder_page.py +11 -0
  95. wagtail/admin/tests/test_collections_views.py +12 -0
  96. wagtail/admin/tests/test_edit_handlers.py +3 -3
  97. wagtail/admin/tests/test_filters.py +2 -2
  98. wagtail/admin/tests/test_keyboard_shortcuts.py +52 -2
  99. wagtail/admin/tests/test_menu.py +0 -2
  100. wagtail/admin/tests/test_privacy.py +16 -16
  101. wagtail/admin/tests/test_templatetags.py +137 -0
  102. wagtail/admin/tests/test_workflows.py +34 -0
  103. wagtail/admin/tests/viewsets/test_model_viewset.py +322 -0
  104. wagtail/admin/ui/tables/orderable.py +73 -0
  105. wagtail/admin/ui/tables/pages.py +3 -13
  106. wagtail/admin/views/collection_privacy.py +6 -2
  107. wagtail/admin/views/generic/__init__.py +1 -0
  108. wagtail/admin/views/generic/mixins.py +20 -2
  109. wagtail/admin/views/generic/models.py +67 -1
  110. wagtail/admin/views/generic/ordering.py +79 -0
  111. wagtail/admin/views/home.py +3 -3
  112. wagtail/admin/views/page_privacy.py +5 -2
  113. wagtail/admin/views/pages/create.py +1 -1
  114. wagtail/admin/views/pages/edit.py +2 -2
  115. wagtail/admin/views/pages/listing.py +7 -42
  116. wagtail/admin/views/pages/move.py +1 -1
  117. wagtail/admin/views/pages/ordering.py +1 -1
  118. wagtail/admin/viewsets/base.py +1 -1
  119. wagtail/admin/viewsets/model.py +49 -1
  120. wagtail/admin/wagtail_hooks.py +2 -1
  121. wagtail/admin/widgets/slug.py +10 -10
  122. wagtail/api/v2/serializers.py +1 -1
  123. wagtail/api/v2/tests/test_renderer_classes.py +32 -0
  124. wagtail/apps.py +2 -0
  125. wagtail/bin/wagtail.py +1 -1
  126. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +14 -14
  127. wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.mo +0 -0
  128. wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.po +19 -2
  129. wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.mo +0 -0
  130. wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.po +18 -1
  131. wagtail/contrib/frontend_cache/tests.py +4 -2
  132. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +4 -4
  133. wagtail/contrib/redirects/tests/test_tmp_storages.py +20 -0
  134. wagtail/contrib/redirects/tmp_storages.py +1 -1
  135. wagtail/contrib/redirects/views.py +3 -3
  136. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +3 -3
  137. wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.mo +0 -0
  138. wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.po +43 -3
  139. wagtail/contrib/search_promotions/static/wagtailsearchpromotions/js/query-chooser-modal.js +1 -1
  140. wagtail/contrib/search_promotions/views/settings.py +2 -2
  141. wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.mo +0 -0
  142. wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.po +6 -1
  143. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +1 -1
  144. wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.mo +0 -0
  145. wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.po +6 -2
  146. wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.mo +0 -0
  147. wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.po +6 -1
  148. wagtail/contrib/settings/tests/site_specific/test_admin.py +40 -6
  149. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  150. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
  151. wagtail/contrib/styleguide/templates/wagtailstyleguide/base.html +5 -5
  152. wagtail/contrib/table_block/blocks.py +1 -0
  153. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +5 -1
  154. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  155. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
  156. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  157. wagtail/coreutils.py +5 -5
  158. wagtail/documents/forms.py +18 -1
  159. wagtail/documents/locale/en/LC_MESSAGES/django.po +10 -10
  160. wagtail/documents/locale/nl/LC_MESSAGES/django.mo +0 -0
  161. wagtail/documents/locale/nl/LC_MESSAGES/django.po +9 -0
  162. wagtail/documents/locale/ru/LC_MESSAGES/django.mo +0 -0
  163. wagtail/documents/locale/ru/LC_MESSAGES/django.po +9 -0
  164. wagtail/documents/models.py +1 -1
  165. wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
  166. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  167. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  168. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  169. wagtail/documents/templates/wagtaildocs/documents/add.html +0 -34
  170. wagtail/documents/tests/test_admin_views.py +132 -26
  171. wagtail/documents/tests/test_collection_privacy.py +18 -4
  172. wagtail/documents/tests/test_form_overrides.py +1 -1
  173. wagtail/documents/tests/test_search.py +21 -8
  174. wagtail/documents/views/documents.py +1 -1
  175. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  176. wagtail/embeds/static/wagtailembeds/js/embed-chooser-modal.js +1 -1
  177. wagtail/images/forms.py +16 -1
  178. wagtail/images/locale/cs/LC_MESSAGES/django.mo +0 -0
  179. wagtail/images/locale/cs/LC_MESSAGES/django.po +12 -1
  180. wagtail/images/locale/en/LC_MESSAGES/django.po +57 -46
  181. wagtail/images/locale/nl/LC_MESSAGES/django.mo +0 -0
  182. wagtail/images/locale/nl/LC_MESSAGES/django.po +37 -14
  183. wagtail/images/locale/ru/LC_MESSAGES/django.mo +0 -0
  184. wagtail/images/locale/ru/LC_MESSAGES/django.po +20 -1
  185. wagtail/images/models.py +1 -1
  186. wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
  187. wagtail/images/static/wagtailimages/js/focal-point-chooser.js +1 -1
  188. wagtail/images/static/wagtailimages/js/image-block.js +1 -1
  189. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  190. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  191. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  192. wagtail/images/static/wagtailimages/js/image-url-generator.js +1 -1
  193. wagtail/images/static/wagtailimages/js/vendor/jquery.Jcrop.min.js +1 -1
  194. wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-image.js +1 -1
  195. wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-validate.js +1 -1
  196. wagtail/images/static/wagtailimages/js/vendor/load-image.min.js +1 -1
  197. wagtail/images/templates/wagtailimages/chooser/chooser.html +22 -13
  198. wagtail/images/templates/wagtailimages/chooser/image_preview_column_cell.html +10 -0
  199. wagtail/images/templates/wagtailimages/chooser/results.html +24 -20
  200. wagtail/images/templates/wagtailimages/chooser/title_column_cell.html +15 -0
  201. wagtail/images/templates/wagtailimages/images/add.html +0 -34
  202. wagtail/images/templates/wagtailimages/images/index.html +3 -3
  203. wagtail/images/templates/wagtailimages/images/index_results.html +1 -1
  204. wagtail/images/templates/wagtailimages/images/layout_toggle_button.html +8 -7
  205. wagtail/images/templatetags/wagtailimages_tags.py +2 -2
  206. wagtail/images/tests/test_admin_views.py +87 -0
  207. wagtail/images/tests/test_form_overrides.py +1 -1
  208. wagtail/images/tests/test_models.py +48 -9
  209. wagtail/images/views/chooser.py +66 -2
  210. wagtail/locale/en/LC_MESSAGES/django.po +55 -55
  211. wagtail/locale/is_IS/LC_MESSAGES/django.mo +0 -0
  212. wagtail/locale/is_IS/LC_MESSAGES/django.po +3 -3
  213. wagtail/locale/nl/LC_MESSAGES/django.mo +0 -0
  214. wagtail/locale/nl/LC_MESSAGES/django.po +11 -2
  215. wagtail/locale/ru/LC_MESSAGES/django.mo +0 -0
  216. wagtail/locale/ru/LC_MESSAGES/django.po +11 -1
  217. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  218. wagtail/locales/locale/nl/LC_MESSAGES/django.mo +0 -0
  219. wagtail/locales/locale/nl/LC_MESSAGES/django.po +12 -1
  220. wagtail/locales/locale/ru/LC_MESSAGES/django.mo +0 -0
  221. wagtail/locales/locale/ru/LC_MESSAGES/django.po +10 -1
  222. wagtail/locales/views.py +2 -2
  223. wagtail/models/orderable.py +10 -0
  224. wagtail/models/pages.py +9 -11
  225. wagtail/models/sites.py +1 -1
  226. wagtail/models/workflows.py +8 -5
  227. wagtail/project_template/home/tests.py +6 -7
  228. wagtail/project_template/project_name/settings/base.py +9 -9
  229. wagtail/project_template/requirements.txt +1 -1
  230. wagtail/query.py +7 -2
  231. wagtail/rich_text/rewriters.py +1 -1
  232. wagtail/search/apps.py +4 -49
  233. wagtail/search/backends/__init__.py +1 -113
  234. wagtail/search/backends/base.py +1 -547
  235. wagtail/search/backends/database/__init__.py +1 -50
  236. wagtail/search/backends/database/fallback.py +1 -253
  237. wagtail/search/backends/database/mysql/mysql.py +1 -700
  238. wagtail/search/backends/database/mysql/query.py +1 -258
  239. wagtail/search/backends/database/postgres/postgres.py +1 -749
  240. wagtail/search/backends/database/postgres/query.py +1 -83
  241. wagtail/search/backends/database/postgres/weights.py +1 -63
  242. wagtail/search/backends/database/sqlite/query.py +1 -294
  243. wagtail/search/backends/database/sqlite/sqlite.py +1 -719
  244. wagtail/search/backends/database/sqlite/utils.py +1 -35
  245. wagtail/search/backends/deprecation.py +45 -0
  246. wagtail/search/backends/elasticsearch7.py +18 -1260
  247. wagtail/search/backends/elasticsearch8.py +21 -96
  248. wagtail/search/backends/elasticsearch9.py +35 -0
  249. wagtail/search/backends/opensearch2.py +35 -0
  250. wagtail/search/backends/opensearch3.py +35 -0
  251. wagtail/search/index.py +1 -358
  252. wagtail/search/locale/en/LC_MESSAGES/django.po +2 -10
  253. wagtail/search/management/commands/update_index.py +1 -205
  254. wagtail/search/management/commands/wagtail_update_index.py +1 -4
  255. wagtail/search/models.py +32 -158
  256. wagtail/search/query.py +1 -114
  257. wagtail/search/queryset.py +1 -43
  258. wagtail/search/signal_handlers.py +1 -24
  259. wagtail/search/tasks.py +1 -10
  260. wagtail/search/tests/test_elasticsearch.py +22 -0
  261. wagtail/search/utils.py +1 -206
  262. wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
  263. wagtail/snippets/locale/en/LC_MESSAGES/django.po +3 -3
  264. wagtail/snippets/locale/ru/LC_MESSAGES/django.mo +0 -0
  265. wagtail/snippets/locale/ru/LC_MESSAGES/django.po +8 -1
  266. wagtail/snippets/locale/tr/LC_MESSAGES/django.mo +0 -0
  267. wagtail/snippets/locale/tr/LC_MESSAGES/django.po +8 -1
  268. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  269. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  270. wagtail/snippets/tests/test_reordering.py +319 -0
  271. wagtail/snippets/tests/test_snippets.py +65 -12
  272. wagtail/snippets/views/snippets.py +16 -0
  273. wagtail/test/numberformat.py +30 -0
  274. wagtail/test/settings.py +35 -12
  275. wagtail/test/testapp/fields.py +12 -0
  276. wagtail/test/testapp/migrations/0056_commentablejsonpage.py +50 -0
  277. wagtail/test/testapp/migrations/0057_featurecompletetoy_sort_order.py +23 -0
  278. wagtail/test/testapp/migrations/0058_customlocktask.py +31 -0
  279. wagtail/test/testapp/models.py +27 -0
  280. wagtail/test/testapp/views.py +3 -1
  281. wagtail/test/utils/page_tests.py +17 -17
  282. wagtail/test/utils/template_tests.py +4 -6
  283. wagtail/test/utils/wagtail_tests.py +1 -2
  284. wagtail/tests/test_page_model.py +15 -0
  285. wagtail/{search/tests → tests}/test_page_search.py +29 -2
  286. wagtail/tests/test_search_fields.py +69 -0
  287. wagtail/tests/test_tests.py +62 -6
  288. wagtail/tests/test_workflow.py +25 -1
  289. wagtail/users/locale/cs/LC_MESSAGES/django.mo +0 -0
  290. wagtail/users/locale/cs/LC_MESSAGES/django.po +3 -0
  291. wagtail/users/locale/en/LC_MESSAGES/django.po +2 -2
  292. wagtail/users/locale/nl/LC_MESSAGES/django.mo +0 -0
  293. wagtail/users/locale/nl/LC_MESSAGES/django.po +6 -3
  294. wagtail/users/locale/ru/LC_MESSAGES/django.mo +0 -0
  295. wagtail/users/locale/ru/LC_MESSAGES/django.po +5 -1
  296. wagtail/users/locale/tr/LC_MESSAGES/django.mo +0 -0
  297. wagtail/users/locale/tr/LC_MESSAGES/django.po +78 -4
  298. wagtail/users/templates/wagtailusers/users/create.html +2 -0
  299. wagtail/users/templates/wagtailusers/users/edit.html +2 -0
  300. wagtail/users/tests/test_admin_views.py +4 -0
  301. wagtail/users/views/users.py +1 -1
  302. {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/METADATA +7 -6
  303. {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/RECORD +309 -315
  304. wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +0 -13
  305. wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +0 -13
  306. wagtail/search/tests/__init__.py +0 -0
  307. wagtail/search/tests/elasticsearch_common_tests.py +0 -251
  308. wagtail/search/tests/test_backends.py +0 -1215
  309. wagtail/search/tests/test_db_backend.py +0 -62
  310. wagtail/search/tests/test_elasticsearch7_backend.py +0 -1452
  311. wagtail/search/tests/test_elasticsearch8_backend.py +0 -15
  312. wagtail/search/tests/test_index_functions.py +0 -256
  313. wagtail/search/tests/test_indexed_class.py +0 -157
  314. wagtail/search/tests/test_mysql_backend.py +0 -192
  315. wagtail/search/tests/test_postgres_backend.py +0 -210
  316. wagtail/search/tests/test_queries.py +0 -332
  317. wagtail/search/tests/test_related_fields.py +0 -102
  318. wagtail/search/tests/test_sqlite_backend.py +0 -52
  319. wagtail/test/search/__init__.py +0 -0
  320. wagtail/test/search/apps.py +0 -9
  321. wagtail/test/search/fixtures/search.json +0 -545
  322. wagtail/test/search/migrations/0001_initial.py +0 -146
  323. wagtail/test/search/migrations/0002_bookunindexed.py +0 -43
  324. wagtail/test/search/migrations/0003_book_summary.py +0 -18
  325. wagtail/test/search/migrations/__init__.py +0 -0
  326. wagtail/test/search/models.py +0 -137
  327. /wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_cell.html → tables/ordering_cell.html} +0 -0
  328. /wagtail/{search/checks.py → checks.py} +0 -0
  329. {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/WHEEL +0 -0
  330. {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/entry_points.txt +0 -0
  331. {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/licenses/LICENSE +0 -0
  332. {wagtail-7.1.2.dist-info → wagtail-7.2rc1.dist-info}/top_level.txt +0 -0
@@ -1,83 +1 @@
1
- from django.contrib.postgres.search import SearchQueryField
2
- from django.db.models.expressions import Expression, Value
3
-
4
-
5
- class LexemeCombinable(Expression):
6
- BITAND = "&"
7
- BITOR = "|"
8
-
9
- def _combine(self, other, connector, reversed, node=None):
10
- if not isinstance(other, LexemeCombinable):
11
- raise TypeError(
12
- f"Lexeme can only be combined with other Lexemes, got {type(other)}."
13
- )
14
- if reversed:
15
- return CombinedLexeme(other, connector, self)
16
- return CombinedLexeme(self, connector, other)
17
-
18
- # On Combinable, these are not implemented to reduce confusion with Q. In
19
- # this case we are actually (ab)using them to do logical combination so
20
- # it's consistent with other usage in Django.
21
- def bitand(self, other):
22
- return self._combine(other, self.BITAND, False)
23
-
24
- def bitor(self, other):
25
- return self._combine(other, self.BITOR, False)
26
-
27
- def __or__(self, other):
28
- return self._combine(other, self.BITOR, False)
29
-
30
- def __and__(self, other):
31
- return self._combine(other, self.BITAND, False)
32
-
33
-
34
- class Lexeme(LexemeCombinable, Value):
35
- _output_field = SearchQueryField()
36
-
37
- def __init__(
38
- self, value, output_field=None, *, invert=False, prefix=False, weight=None
39
- ):
40
- self.prefix = prefix
41
- self.invert = invert
42
- self.weight = weight
43
- super().__init__(value, output_field=output_field)
44
-
45
- def as_sql(self, compiler, connection):
46
- param = "'%s'" % self.value.replace("'", "''").replace("\\", "\\\\")
47
-
48
- template = "%s"
49
-
50
- label = ""
51
- if self.prefix:
52
- label += "*"
53
- if self.weight:
54
- label += self.weight
55
-
56
- if label:
57
- param = f"{param}:{label}"
58
- if self.invert:
59
- param = f"!{param}"
60
-
61
- return template, [param]
62
-
63
-
64
- class CombinedLexeme(LexemeCombinable):
65
- _output_field = SearchQueryField()
66
-
67
- def __init__(self, lhs, connector, rhs, output_field=None):
68
- super().__init__(output_field=output_field)
69
- self.connector = connector
70
- self.lhs = lhs
71
- self.rhs = rhs
72
-
73
- def as_sql(self, compiler, connection):
74
- value_params = []
75
- lsql, params = compiler.compile(self.lhs)
76
- value_params.extend(params)
77
-
78
- rsql, params = compiler.compile(self.rhs)
79
- value_params.extend(params)
80
-
81
- combined_sql = f"({lsql} {self.connector} {rsql})"
82
- combined_value = combined_sql % tuple(value_params)
83
- return "%s", [combined_value]
1
+ from wagtailmodelsearch.backends.database.postgres.query import * # noqa: F403
@@ -1,63 +1 @@
1
- from itertools import zip_longest
2
-
3
- from django.apps import apps
4
-
5
- from wagtail.search.index import Indexed
6
- from wagtail.search.utils import get_search_fields
7
-
8
- # This file contains the implementation of weights for PostgreSQL tsvectors. Only PostgreSQL has support for them, so that's why we define them here.
9
-
10
-
11
- WEIGHTS = "ABCD"
12
- WEIGHTS_COUNT = len(WEIGHTS)
13
- # These are filled when apps are ready.
14
- BOOSTS_WEIGHTS = []
15
- WEIGHTS_VALUES = []
16
-
17
-
18
- def get_boosts():
19
- boosts = set()
20
- for model in apps.get_models():
21
- if issubclass(model, Indexed):
22
- for search_field in get_search_fields(model.get_search_fields()):
23
- boost = search_field.boost
24
- if boost is not None:
25
- boosts.add(boost)
26
- return boosts
27
-
28
-
29
- def determine_boosts_weights(boosts=()):
30
- if not boosts:
31
- boosts = get_boosts()
32
- boosts = sorted(boosts, reverse=True)
33
- min_boost = boosts[-1]
34
- if len(boosts) <= WEIGHTS_COUNT:
35
- return list(zip_longest(boosts, WEIGHTS, fillvalue=min(min_boost, 0)))
36
- max_boost = boosts[0]
37
- boost_step = (max_boost - min_boost) / (WEIGHTS_COUNT - 1)
38
- return [(max_boost - (i * boost_step), weight) for i, weight in enumerate(WEIGHTS)]
39
-
40
-
41
- def set_weights():
42
- BOOSTS_WEIGHTS.extend(determine_boosts_weights())
43
- weights = [w for w, c in BOOSTS_WEIGHTS]
44
- min_weight = min(weights)
45
- if min_weight <= 0:
46
- if min_weight == 0:
47
- min_weight = -0.1
48
- weights = [w - min_weight for w in weights]
49
- max_weight = max(weights)
50
- WEIGHTS_VALUES.extend([w / max_weight for w in reversed(weights)])
51
-
52
-
53
- def get_weight(boost):
54
- if boost is None:
55
- return WEIGHTS[-1]
56
- for max_boost, weight in BOOSTS_WEIGHTS:
57
- if boost >= max_boost:
58
- return weight
59
- return weight
60
-
61
-
62
- def get_sql_weights():
63
- return "{" + ",".join(map(str, WEIGHTS_VALUES)) + "}"
1
+ from wagtailmodelsearch.backends.database.postgres.weights import * # noqa: F403
@@ -1,294 +1 @@
1
- from typing import Any
2
-
3
- from django.db.backends.base.base import BaseDatabaseWrapper
4
- from django.db.models.expressions import CombinedExpression, Expression, Func, Value
5
- from django.db.models.fields import BooleanField, Field, FloatField
6
- from django.db.models.sql.compiler import SQLCompiler
7
-
8
- from wagtail.search.query import And, MatchAll, Not, Or, Phrase, PlainText, SearchQuery
9
-
10
-
11
- class BM25(Func):
12
- function = "bm25"
13
- output_field = FloatField()
14
-
15
- def __init__(self):
16
- expressions = ()
17
- super().__init__(*expressions)
18
-
19
- def as_sql(
20
- self,
21
- compiler: SQLCompiler,
22
- connection: BaseDatabaseWrapper,
23
- function=None,
24
- template=None,
25
- ):
26
- sql, params = "bm25(wagtailsearch_indexentry_fts)", []
27
- return sql, params
28
-
29
-
30
- class LexemeCombinable(Expression):
31
- BITAND = "AND"
32
- BITOR = "OR"
33
-
34
- def _combine(self, other, connector, reversed, node=None):
35
- if not isinstance(other, LexemeCombinable):
36
- raise TypeError(
37
- f"Lexeme can only be combined with other Lexemes, got {type(other)}."
38
- )
39
- if reversed:
40
- return CombinedLexeme(other, connector, self)
41
- return CombinedLexeme(self, connector, other)
42
-
43
- # On Combinable, these are not implemented to reduce confusion with Q. In
44
- # this case we are actually (ab)using them to do logical combination so
45
- # it's consistent with other usage in Django.
46
- def bitand(self, other):
47
- return self._combine(other, self.BITAND, False)
48
-
49
- def bitor(self, other):
50
- return self._combine(other, self.BITOR, False)
51
-
52
- def __or__(self, other):
53
- return self._combine(other, self.BITOR, False)
54
-
55
- def __and__(self, other):
56
- return self._combine(other, self.BITAND, False)
57
-
58
-
59
- class SearchQueryField(Field):
60
- def db_type(self, connection):
61
- return None
62
-
63
-
64
- class Lexeme(LexemeCombinable, Value):
65
- _output_field = SearchQueryField()
66
-
67
- def __init__(self, value, output_field=None, *, prefix=False, weight=None):
68
- self.prefix = prefix
69
- self.weight = weight
70
- super().__init__(value, output_field=output_field)
71
-
72
- def as_sql(self, compiler, connection):
73
- param = self.value.replace("'", "''").replace("\\", "\\\\")
74
-
75
- if self.prefix:
76
- template = '"%s"*'
77
- else:
78
- template = '"%s"'
79
-
80
- return template, [param]
81
-
82
-
83
- class CombinedLexeme(LexemeCombinable):
84
- _output_field = SearchQueryField()
85
-
86
- def __init__(self, lhs, connector, rhs, output_field=None):
87
- super().__init__(output_field=output_field)
88
- self.connector = connector
89
- self.lhs = lhs
90
- self.rhs = rhs
91
-
92
- def as_sql(self, compiler, connection):
93
- value_params = []
94
- lsql, params = compiler.compile(self.lhs)
95
- value_params.extend(params)
96
-
97
- rsql, params = compiler.compile(self.rhs)
98
- value_params.extend(params)
99
-
100
- combined_sql = f"{lsql} {self.connector} {rsql}"
101
- combined_value = combined_sql % tuple(value_params)
102
- return "%s", [combined_value]
103
-
104
-
105
- class SearchQueryCombinable:
106
- BITAND = "AND"
107
- BITOR = "OR"
108
-
109
- def _combine(self, other, connector: str, reversed: bool = False):
110
- if not isinstance(other, SearchQueryCombinable):
111
- raise TypeError(
112
- "SearchQuery can only be combined with other SearchQuery "
113
- "instances, got %s." % type(other).__name__
114
- )
115
- if reversed:
116
- return CombinedSearchQueryExpression(other, connector, self)
117
- return CombinedSearchQueryExpression(self, connector, other)
118
-
119
- # On Combinable, these are not implemented to reduce confusion with Q. In
120
- # this case we are actually (ab)using them to do logical combination so
121
- # it's consistent with other usage in Django.
122
- def __or__(self, other):
123
- return self._combine(other, self.BITOR, False)
124
-
125
- def __ror__(self, other):
126
- return self._combine(other, self.BITOR, True)
127
-
128
- def __and__(self, other):
129
- return self._combine(other, self.BITAND, False)
130
-
131
- def __rand__(self, other):
132
- return self._combine(other, self.BITAND, True)
133
-
134
-
135
- class SearchQueryExpression(SearchQueryCombinable, Expression):
136
- def __init__(self, value: LexemeCombinable, using=None, **extra):
137
- super().__init__(output_field=SearchQueryField())
138
- self.using = using
139
- self.extra = extra
140
- if isinstance(value, str): # If the value is a string, we assume it's a phrase
141
- self.value = Value(
142
- '"%s"' % value
143
- ) # We wrap it in quotes to make sure it's parsed as a phrase
144
- else: # Otherwise, we assume it's a lexeme
145
- self.value = value
146
-
147
- def as_sql(
148
- self,
149
- compiler: SQLCompiler,
150
- connection: BaseDatabaseWrapper,
151
- **extra_context: Any,
152
- ) -> tuple[str, list[Any]]:
153
- sql, params = compiler.compile(self.value)
154
- return (sql, params)
155
-
156
- def __repr__(self) -> str:
157
- return self.value.__repr__()
158
-
159
-
160
- class CombinedSearchQueryExpression(SearchQueryCombinable, CombinedExpression):
161
- def __init__(self, lhs, connector, rhs, output_field=None):
162
- super().__init__(lhs, connector, rhs, output_field)
163
-
164
- def __str__(self):
165
- return "(%s)" % super().__str__()
166
-
167
-
168
- class MatchExpression(Expression):
169
- filterable = True
170
- template = (
171
- "wagtailsearch_indexentry_fts MATCH %s" # TODO: Can the table name be inferred?
172
- )
173
- output_field = BooleanField()
174
-
175
- def __init__(self, columns: list[str], query: SearchQueryCombinable) -> None:
176
- super().__init__(output_field=self.output_field)
177
- self.columns = columns
178
- self.query = query
179
-
180
- def as_sql(self, compiler, connection):
181
- joined_columns = " ".join(
182
- self.columns
183
- ) # The format of the columns is 'column1 column2'
184
- compiled_query = compiler.compile(self.query) # Compile the query to a string
185
- formatted_query = compiled_query[0] % tuple(
186
- compiled_query[1]
187
- ) # Substitute the params in the query
188
- params = [
189
- "{{{column}}} : ({query})".format(
190
- column=joined_columns, query=formatted_query
191
- )
192
- ] # Build the full MATCH search query. It will be a parameter to the template, so no SQL injections are possible here.
193
- return (self.template, params)
194
-
195
- def __repr__(self):
196
- return f"<MatchExpression: {self.columns!r} = {self.query!r}>"
197
-
198
-
199
- class AndNot(SearchQuery):
200
- """
201
- This is a binary search query, where there are two subqueries, and the search is done by searching the first, and excluding the second subquery.
202
- For example, AndNot(X, Y) would be equivalent to doing And(X, Not(Y)), where X is the first subquery, and Y is the second subquery (the negated one).
203
- This is done because the SQLite FTS5 module doesn't support the unary NOT operator.
204
- """
205
-
206
- def __init__(self, subquery_a: SearchQuery, subquery_b: SearchQuery):
207
- self.subquery_a = subquery_a
208
- self.subquery_b = subquery_b
209
-
210
- def __repr__(self):
211
- return f"<{repr(self.subquery_a)} AndNot {repr(self.subquery_b)}>"
212
-
213
-
214
- def normalize(search_query: SearchQuery) -> tuple[SearchQuery]:
215
- """
216
- Turns this query into a normalized version.
217
- For example, And(Not(PlainText("Arepa")), PlainText("Crepe")) would be turned into AndNot(PlainText("Crepe"), PlainText("Arepa")): "Crepe AND NOT Arepa".
218
- This is done because we need to get the NOT operator to the front of the query, so it can be used in the search, because the SQLite FTS5 module doesn't support the unary NOT operator. This means that, in order to support the NOT operator, we need to match against the non-negated version of the query, and then return everything that is not in the results of the non-negated query.
219
- """
220
- if isinstance(search_query, Phrase):
221
- return search_query # We can't normalize a Phrase.
222
- if isinstance(search_query, PlainText):
223
- return search_query # We can't normalize a PlainText.
224
- if isinstance(search_query, And):
225
- normalized_subqueries: list[SearchQuery] = [
226
- normalize(subquery) for subquery in search_query.subqueries
227
- ] # This builds a list of normalized subqueries.
228
-
229
- not_negated_subqueries = [
230
- subquery
231
- for subquery in normalized_subqueries
232
- if not isinstance(subquery, Not)
233
- ] # All the non-negated subqueries.
234
- not_negated_subqueries = [
235
- subquery
236
- for subquery in not_negated_subqueries
237
- if not isinstance(subquery, MatchAll)
238
- ] # We can ignore all MatchAll SearchQueries here, because they are redundant.
239
- negated_subqueries = [
240
- subquery.subquery
241
- for subquery in normalized_subqueries
242
- if isinstance(subquery, Not)
243
- ]
244
-
245
- if (
246
- negated_subqueries == []
247
- ): # If there are no negated subqueries, return an And(), now without the redundant MatchAll subqueries.
248
- return And(not_negated_subqueries)
249
-
250
- for subquery in (
251
- negated_subqueries
252
- ): # If there's a negated MatchAll subquery, then nothing will get matched.
253
- if isinstance(subquery, MatchAll):
254
- return Not(MatchAll())
255
-
256
- return AndNot(And(not_negated_subqueries), Or(negated_subqueries))
257
- if isinstance(search_query, Or):
258
- normalized_subqueries: list[SearchQuery] = [
259
- normalize(subquery) for subquery in search_query.subqueries
260
- ] # This builds a list of (subquery, negated) tuples.
261
-
262
- negated_subqueries = [
263
- subquery.subquery
264
- for subquery in normalized_subqueries
265
- if isinstance(subquery, Not)
266
- ]
267
- if (
268
- negated_subqueries == []
269
- ): # If there are no negated subqueries, return an Or().
270
- return Or(normalized_subqueries)
271
-
272
- for subquery in (
273
- negated_subqueries
274
- ): # If there's a MatchAll subquery, then anything will get matched.
275
- if isinstance(subquery, MatchAll):
276
- return MatchAll()
277
-
278
- not_negated_subqueries = [
279
- subquery
280
- for subquery in normalized_subqueries
281
- if not isinstance(subquery, Not)
282
- ] # All the non-negated subqueries.
283
- not_negated_subqueries = [
284
- subquery
285
- for subquery in not_negated_subqueries
286
- if not isinstance(subquery, MatchAll)
287
- ] # We can ignore all MatchAll SearchQueries here, because they are redundant.
288
-
289
- return AndNot(MatchAll(), And(negated_subqueries))
290
- if isinstance(search_query, Not):
291
- normalized = normalize(search_query.subquery)
292
- return Not(normalized) # Normalize the subquery, then invert it.
293
- if isinstance(search_query, MatchAll):
294
- return search_query # We can't normalize a MatchAll.
1
+ from wagtailmodelsearch.backends.database.sqlite.query import * # noqa: F403