wagtail 7.1.2__py3-none-any.whl → 7.2__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 (1125) 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/ar/LC_MESSAGES/django.mo +0 -0
  19. wagtail/admin/locale/ar/LC_MESSAGES/django.po +44 -89
  20. wagtail/admin/locale/az_AZ/LC_MESSAGES/django.mo +0 -0
  21. wagtail/admin/locale/az_AZ/LC_MESSAGES/django.po +4 -7
  22. wagtail/admin/locale/be/LC_MESSAGES/django.mo +0 -0
  23. wagtail/admin/locale/be/LC_MESSAGES/django.po +15 -42
  24. wagtail/admin/locale/bg/LC_MESSAGES/django.mo +0 -0
  25. wagtail/admin/locale/bg/LC_MESSAGES/django.po +7 -16
  26. wagtail/admin/locale/bn/LC_MESSAGES/django.mo +0 -0
  27. wagtail/admin/locale/bn/LC_MESSAGES/django.po +4 -13
  28. wagtail/admin/locale/ca/LC_MESSAGES/django.mo +0 -0
  29. wagtail/admin/locale/ca/LC_MESSAGES/django.po +159 -74
  30. wagtail/admin/locale/ca/LC_MESSAGES/djangojs.mo +0 -0
  31. wagtail/admin/locale/ca/LC_MESSAGES/djangojs.po +11 -0
  32. wagtail/admin/locale/cs/LC_MESSAGES/django.mo +0 -0
  33. wagtail/admin/locale/cs/LC_MESSAGES/django.po +40 -50
  34. wagtail/admin/locale/cy/LC_MESSAGES/django.mo +0 -0
  35. wagtail/admin/locale/cy/LC_MESSAGES/django.po +6 -13
  36. wagtail/admin/locale/da/LC_MESSAGES/django.mo +0 -0
  37. wagtail/admin/locale/da/LC_MESSAGES/django.po +10 -22
  38. wagtail/admin/locale/de/LC_MESSAGES/django.mo +0 -0
  39. wagtail/admin/locale/de/LC_MESSAGES/django.po +42 -93
  40. wagtail/admin/locale/dv/LC_MESSAGES/django.mo +0 -0
  41. wagtail/admin/locale/dv/LC_MESSAGES/django.po +26 -64
  42. wagtail/admin/locale/el/LC_MESSAGES/django.mo +0 -0
  43. wagtail/admin/locale/el/LC_MESSAGES/django.po +9 -31
  44. wagtail/admin/locale/en/LC_MESSAGES/django.po +278 -192
  45. wagtail/admin/locale/en/LC_MESSAGES/djangojs.po +29 -15
  46. wagtail/admin/locale/es/LC_MESSAGES/django.mo +0 -0
  47. wagtail/admin/locale/es/LC_MESSAGES/django.po +17 -52
  48. wagtail/admin/locale/es_419/LC_MESSAGES/django.mo +0 -0
  49. wagtail/admin/locale/es_419/LC_MESSAGES/django.po +4 -22
  50. wagtail/admin/locale/es_VE/LC_MESSAGES/django.mo +0 -0
  51. wagtail/admin/locale/es_VE/LC_MESSAGES/django.po +4 -7
  52. wagtail/admin/locale/et/LC_MESSAGES/django.mo +0 -0
  53. wagtail/admin/locale/et/LC_MESSAGES/django.po +15 -42
  54. wagtail/admin/locale/eu/LC_MESSAGES/django.po +1 -1
  55. wagtail/admin/locale/fa/LC_MESSAGES/django.mo +0 -0
  56. wagtail/admin/locale/fa/LC_MESSAGES/django.po +12 -50
  57. wagtail/admin/locale/fi/LC_MESSAGES/django.mo +0 -0
  58. wagtail/admin/locale/fi/LC_MESSAGES/django.po +43 -70
  59. wagtail/admin/locale/fi/LC_MESSAGES/djangojs.mo +0 -0
  60. wagtail/admin/locale/fi/LC_MESSAGES/djangojs.po +17 -0
  61. wagtail/admin/locale/fr/LC_MESSAGES/django.mo +0 -0
  62. wagtail/admin/locale/fr/LC_MESSAGES/django.po +157 -74
  63. wagtail/admin/locale/fr/LC_MESSAGES/djangojs.mo +0 -0
  64. wagtail/admin/locale/fr/LC_MESSAGES/djangojs.po +11 -0
  65. wagtail/admin/locale/gl/LC_MESSAGES/django.mo +0 -0
  66. wagtail/admin/locale/gl/LC_MESSAGES/django.po +155 -72
  67. wagtail/admin/locale/gl/LC_MESSAGES/djangojs.mo +0 -0
  68. wagtail/admin/locale/gl/LC_MESSAGES/djangojs.po +11 -0
  69. wagtail/admin/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  70. wagtail/admin/locale/he_IL/LC_MESSAGES/django.po +7 -28
  71. wagtail/admin/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  72. wagtail/admin/locale/hr_HR/LC_MESSAGES/django.po +15 -38
  73. wagtail/admin/locale/ht/LC_MESSAGES/django.po +4 -4
  74. wagtail/admin/locale/hu/LC_MESSAGES/django.mo +0 -0
  75. wagtail/admin/locale/hu/LC_MESSAGES/django.po +44 -91
  76. wagtail/admin/locale/id_ID/LC_MESSAGES/django.mo +0 -0
  77. wagtail/admin/locale/id_ID/LC_MESSAGES/django.po +10 -31
  78. wagtail/admin/locale/is_IS/LC_MESSAGES/django.mo +0 -0
  79. wagtail/admin/locale/is_IS/LC_MESSAGES/django.po +41 -87
  80. wagtail/admin/locale/it/LC_MESSAGES/django.mo +0 -0
  81. wagtail/admin/locale/it/LC_MESSAGES/django.po +34 -78
  82. wagtail/admin/locale/ja/LC_MESSAGES/django.mo +0 -0
  83. wagtail/admin/locale/ja/LC_MESSAGES/django.po +15 -42
  84. wagtail/admin/locale/ka/LC_MESSAGES/django.po +4 -4
  85. wagtail/admin/locale/ko/LC_MESSAGES/django.mo +0 -0
  86. wagtail/admin/locale/ko/LC_MESSAGES/django.po +20 -57
  87. wagtail/admin/locale/lt/LC_MESSAGES/django.mo +0 -0
  88. wagtail/admin/locale/lt/LC_MESSAGES/django.po +12 -31
  89. wagtail/admin/locale/lv/LC_MESSAGES/django.mo +0 -0
  90. wagtail/admin/locale/lv/LC_MESSAGES/django.po +9 -40
  91. wagtail/admin/locale/mi/LC_MESSAGES/django.mo +0 -0
  92. wagtail/admin/locale/mi/LC_MESSAGES/django.po +6 -10
  93. wagtail/admin/locale/mn/LC_MESSAGES/django.mo +0 -0
  94. wagtail/admin/locale/mn/LC_MESSAGES/django.po +10 -43
  95. wagtail/admin/locale/my/LC_MESSAGES/django.po +4 -4
  96. wagtail/admin/locale/nb/LC_MESSAGES/django.mo +0 -0
  97. wagtail/admin/locale/nb/LC_MESSAGES/django.po +15 -53
  98. wagtail/admin/locale/nl/LC_MESSAGES/django.mo +0 -0
  99. wagtail/admin/locale/nl/LC_MESSAGES/django.po +208 -70
  100. wagtail/admin/locale/nl/LC_MESSAGES/djangojs.mo +0 -0
  101. wagtail/admin/locale/nl/LC_MESSAGES/djangojs.po +19 -2
  102. wagtail/admin/locale/pl/LC_MESSAGES/django.mo +0 -0
  103. wagtail/admin/locale/pl/LC_MESSAGES/django.po +27 -72
  104. wagtail/admin/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  105. wagtail/admin/locale/pt_BR/LC_MESSAGES/django.po +38 -83
  106. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  107. wagtail/admin/locale/pt_PT/LC_MESSAGES/django.po +17 -56
  108. wagtail/admin/locale/ro/LC_MESSAGES/django.mo +0 -0
  109. wagtail/admin/locale/ro/LC_MESSAGES/django.po +23 -68
  110. wagtail/admin/locale/ru/LC_MESSAGES/django.mo +0 -0
  111. wagtail/admin/locale/ru/LC_MESSAGES/django.po +96 -84
  112. wagtail/admin/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  113. wagtail/admin/locale/sk_SK/LC_MESSAGES/django.po +9 -28
  114. wagtail/admin/locale/sl/LC_MESSAGES/django.mo +0 -0
  115. wagtail/admin/locale/sl/LC_MESSAGES/django.po +45 -90
  116. wagtail/admin/locale/sv/LC_MESSAGES/django.mo +0 -0
  117. wagtail/admin/locale/sv/LC_MESSAGES/django.po +27 -72
  118. wagtail/admin/locale/tet/LC_MESSAGES/django.mo +0 -0
  119. wagtail/admin/locale/tet/LC_MESSAGES/django.po +12 -22
  120. wagtail/admin/locale/th/LC_MESSAGES/django.mo +0 -0
  121. wagtail/admin/locale/th/LC_MESSAGES/django.po +10 -42
  122. wagtail/admin/locale/tr/LC_MESSAGES/django.mo +0 -0
  123. wagtail/admin/locale/tr/LC_MESSAGES/django.po +64 -70
  124. wagtail/admin/locale/tr_TR/LC_MESSAGES/django.mo +0 -0
  125. wagtail/admin/locale/tr_TR/LC_MESSAGES/django.po +15 -42
  126. wagtail/admin/locale/ug/LC_MESSAGES/django.mo +0 -0
  127. wagtail/admin/locale/ug/LC_MESSAGES/django.po +38 -83
  128. wagtail/admin/locale/uk/LC_MESSAGES/django.mo +0 -0
  129. wagtail/admin/locale/uk/LC_MESSAGES/django.po +15 -45
  130. wagtail/admin/locale/vi/LC_MESSAGES/django.mo +0 -0
  131. wagtail/admin/locale/vi/LC_MESSAGES/django.po +4 -17
  132. wagtail/admin/locale/zh/LC_MESSAGES/django.mo +0 -0
  133. wagtail/admin/locale/zh/LC_MESSAGES/django.po +7 -19
  134. wagtail/admin/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  135. wagtail/admin/locale/zh_Hans/LC_MESSAGES/django.po +17 -54
  136. wagtail/admin/locale/zh_Hant/LC_MESSAGES/django.mo +0 -0
  137. wagtail/admin/locale/zh_Hant/LC_MESSAGES/django.po +15 -37
  138. wagtail/admin/static/wagtailadmin/css/core.css +1 -1
  139. wagtail/admin/static/wagtailadmin/js/bulk-actions.js +1 -1
  140. wagtail/admin/static/wagtailadmin/js/chooser-modal.js +1 -1
  141. wagtail/admin/static/wagtailadmin/js/chooser-widget-telepath.js +1 -1
  142. wagtail/admin/static/wagtailadmin/js/chooser-widget.js +1 -1
  143. wagtail/admin/static/wagtailadmin/js/comments.js +1 -1
  144. wagtail/admin/static/wagtailadmin/js/core.js +1 -1
  145. wagtail/admin/static/wagtailadmin/js/core.js.LICENSE.txt +2 -2
  146. wagtail/admin/static/wagtailadmin/js/date-time-chooser.js +1 -1
  147. wagtail/admin/static/wagtailadmin/js/draftail.js +1 -1
  148. wagtail/admin/static/wagtailadmin/js/filtered-select.js +1 -1
  149. wagtail/admin/static/wagtailadmin/js/icons.js +1 -1
  150. wagtail/admin/static/wagtailadmin/js/modal-workflow.js +1 -1
  151. wagtail/admin/static/wagtailadmin/js/page-chooser-modal.js +1 -1
  152. wagtail/admin/static/wagtailadmin/js/page-chooser-telepath.js +1 -1
  153. wagtail/admin/static/wagtailadmin/js/page-chooser.js +1 -1
  154. wagtail/admin/static/wagtailadmin/js/privacy-switch.js +1 -1
  155. wagtail/admin/static/wagtailadmin/js/sidebar.js +1 -1
  156. wagtail/admin/static/wagtailadmin/js/task-chooser-modal.js +1 -1
  157. wagtail/admin/static/wagtailadmin/js/task-chooser.js +1 -1
  158. wagtail/admin/static/wagtailadmin/js/telepath/blocks.js +1 -1
  159. wagtail/admin/static/wagtailadmin/js/telepath/telepath.js +1 -1
  160. wagtail/admin/static/wagtailadmin/js/telepath/widgets.js +1 -1
  161. wagtail/admin/static/wagtailadmin/js/userbar.js +1 -1
  162. wagtail/admin/static/wagtailadmin/js/userbar.js.LICENSE.txt +2 -2
  163. wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-modal.js +1 -1
  164. wagtail/admin/static/wagtailadmin/js/vendor/bootstrap-transition.js +1 -1
  165. wagtail/admin/static/wagtailadmin/js/vendor/jquery-3.6.0.min.js +1 -1
  166. wagtail/admin/static/wagtailadmin/js/vendor/jquery-ui-1.13.2.min.js +1 -1
  167. wagtail/admin/static/wagtailadmin/js/vendor/jquery.datetimepicker.js +1 -1
  168. wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload-process.js +1 -1
  169. wagtail/admin/static/wagtailadmin/js/vendor/jquery.fileupload.js +1 -1
  170. wagtail/admin/static/wagtailadmin/js/vendor/jquery.iframe-transport.js +1 -1
  171. wagtail/admin/static/wagtailadmin/js/vendor/tag-it.js +1 -1
  172. wagtail/admin/static/wagtailadmin/js/vendor.js +1 -1
  173. wagtail/admin/static/wagtailadmin/js/vendor.js.LICENSE.txt +1 -1
  174. wagtail/admin/static/wagtailadmin/js/wagtailadmin.js +1 -1
  175. wagtail/admin/static/wagtailadmin/js/workflow-action.js +1 -1
  176. wagtail/admin/templates/wagtailadmin/account/account.html +2 -0
  177. wagtail/admin/templates/wagtailadmin/base.html +14 -0
  178. wagtail/admin/templates/wagtailadmin/generic/chooser/chooser.html +2 -1
  179. wagtail/admin/templates/wagtailadmin/generic/chooser/creation_form.html +2 -1
  180. wagtail/admin/templates/wagtailadmin/panels/multi_field_panel_child.html +1 -1
  181. wagtail/admin/templates/wagtailadmin/panels/object_list.html +1 -1
  182. wagtail/admin/templates/wagtailadmin/panels/tabbed_interface.html +3 -2
  183. wagtail/admin/templates/wagtailadmin/shared/formatted_field.html +1 -1
  184. wagtail/admin/templates/wagtailadmin/shared/forms/single_checkbox.html +1 -1
  185. wagtail/admin/templates/wagtailadmin/shared/keyboard_shortcuts_dialog.html +19 -0
  186. wagtail/admin/templates/wagtailadmin/shared/panel.html +1 -1
  187. wagtail/admin/templates/wagtailadmin/shared/set_privacy.html +15 -0
  188. wagtail/admin/templates/wagtailadmin/shared/side_panels/checks.html +28 -1
  189. wagtail/admin/templates/wagtailadmin/shared/workflow_history/detail.html +2 -2
  190. wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_header.html → tables/ordering_header.html} +2 -2
  191. wagtail/admin/templates/wagtailadmin/tables/title_cell.html +1 -1
  192. wagtail/admin/templates/wagtailadmin/widgets/{daterange_input.html → range_input.html} +1 -1
  193. wagtail/admin/templates/wagtailadmin/workflows/task_chooser/chooser.html +4 -2
  194. wagtail/admin/templatetags/wagtailadmin_tags.py +41 -22
  195. wagtail/admin/tests/api/test_pages.py +7 -7
  196. wagtail/admin/tests/api/test_renderer_classes.py +16 -0
  197. wagtail/admin/tests/pages/test_create_page.py +42 -2
  198. wagtail/admin/tests/pages/test_edit_page.py +128 -14
  199. wagtail/admin/tests/pages/test_explorer_view.py +34 -7
  200. wagtail/admin/tests/pages/test_reorder_page.py +11 -0
  201. wagtail/admin/tests/test_collections_views.py +12 -0
  202. wagtail/admin/tests/test_edit_handlers.py +3 -3
  203. wagtail/admin/tests/test_filters.py +2 -2
  204. wagtail/admin/tests/test_keyboard_shortcuts.py +52 -2
  205. wagtail/admin/tests/test_menu.py +0 -2
  206. wagtail/admin/tests/test_privacy.py +16 -16
  207. wagtail/admin/tests/test_templatetags.py +137 -0
  208. wagtail/admin/tests/test_workflows.py +34 -0
  209. wagtail/admin/tests/viewsets/test_model_viewset.py +322 -0
  210. wagtail/admin/ui/tables/orderable.py +73 -0
  211. wagtail/admin/ui/tables/pages.py +3 -13
  212. wagtail/admin/views/collection_privacy.py +6 -2
  213. wagtail/admin/views/generic/__init__.py +1 -0
  214. wagtail/admin/views/generic/mixins.py +20 -2
  215. wagtail/admin/views/generic/models.py +67 -1
  216. wagtail/admin/views/generic/ordering.py +79 -0
  217. wagtail/admin/views/home.py +3 -3
  218. wagtail/admin/views/page_privacy.py +5 -2
  219. wagtail/admin/views/pages/create.py +1 -1
  220. wagtail/admin/views/pages/edit.py +2 -2
  221. wagtail/admin/views/pages/listing.py +7 -42
  222. wagtail/admin/views/pages/move.py +1 -1
  223. wagtail/admin/views/pages/ordering.py +1 -1
  224. wagtail/admin/viewsets/base.py +1 -1
  225. wagtail/admin/viewsets/model.py +49 -1
  226. wagtail/admin/wagtail_hooks.py +2 -1
  227. wagtail/admin/widgets/slug.py +10 -10
  228. wagtail/api/v2/serializers.py +1 -1
  229. wagtail/api/v2/tests/test_renderer_classes.py +32 -0
  230. wagtail/apps.py +2 -0
  231. wagtail/bin/wagtail.py +1 -1
  232. wagtail/contrib/forms/locale/af/LC_MESSAGES/django.po +1 -1
  233. wagtail/contrib/forms/locale/ar/LC_MESSAGES/django.po +1 -1
  234. wagtail/contrib/forms/locale/az_AZ/LC_MESSAGES/django.po +1 -1
  235. wagtail/contrib/forms/locale/be/LC_MESSAGES/django.po +1 -1
  236. wagtail/contrib/forms/locale/bg/LC_MESSAGES/django.po +1 -1
  237. wagtail/contrib/forms/locale/bn/LC_MESSAGES/django.po +1 -1
  238. wagtail/contrib/forms/locale/ca/LC_MESSAGES/django.po +1 -1
  239. wagtail/contrib/forms/locale/cs/LC_MESSAGES/django.po +1 -1
  240. wagtail/contrib/forms/locale/cy/LC_MESSAGES/django.po +1 -1
  241. wagtail/contrib/forms/locale/da/LC_MESSAGES/django.po +1 -1
  242. wagtail/contrib/forms/locale/de/LC_MESSAGES/django.po +1 -1
  243. wagtail/contrib/forms/locale/dv/LC_MESSAGES/django.po +1 -1
  244. wagtail/contrib/forms/locale/el/LC_MESSAGES/django.po +1 -1
  245. wagtail/contrib/forms/locale/en/LC_MESSAGES/django.po +14 -14
  246. wagtail/contrib/forms/locale/es/LC_MESSAGES/django.po +1 -1
  247. wagtail/contrib/forms/locale/es_419/LC_MESSAGES/django.po +1 -1
  248. wagtail/contrib/forms/locale/et/LC_MESSAGES/django.po +1 -1
  249. wagtail/contrib/forms/locale/eu/LC_MESSAGES/django.po +1 -1
  250. wagtail/contrib/forms/locale/fa/LC_MESSAGES/django.po +1 -1
  251. wagtail/contrib/forms/locale/fi/LC_MESSAGES/django.po +1 -1
  252. wagtail/contrib/forms/locale/fr/LC_MESSAGES/django.po +1 -1
  253. wagtail/contrib/forms/locale/gl/LC_MESSAGES/django.po +1 -1
  254. wagtail/contrib/forms/locale/he_IL/LC_MESSAGES/django.po +1 -1
  255. wagtail/contrib/forms/locale/hr_HR/LC_MESSAGES/django.po +1 -1
  256. wagtail/contrib/forms/locale/ht/LC_MESSAGES/django.po +1 -1
  257. wagtail/contrib/forms/locale/hu/LC_MESSAGES/django.po +1 -1
  258. wagtail/contrib/forms/locale/hy/LC_MESSAGES/django.po +1 -1
  259. wagtail/contrib/forms/locale/id_ID/LC_MESSAGES/django.po +1 -1
  260. wagtail/contrib/forms/locale/is_IS/LC_MESSAGES/django.po +1 -1
  261. wagtail/contrib/forms/locale/it/LC_MESSAGES/django.po +1 -1
  262. wagtail/contrib/forms/locale/ja/LC_MESSAGES/django.po +1 -1
  263. wagtail/contrib/forms/locale/ka/LC_MESSAGES/django.po +1 -1
  264. wagtail/contrib/forms/locale/ko/LC_MESSAGES/django.po +1 -1
  265. wagtail/contrib/forms/locale/lt/LC_MESSAGES/django.po +1 -1
  266. wagtail/contrib/forms/locale/lv/LC_MESSAGES/django.po +1 -1
  267. wagtail/contrib/forms/locale/mi/LC_MESSAGES/django.po +1 -1
  268. wagtail/contrib/forms/locale/mn/LC_MESSAGES/django.po +1 -1
  269. wagtail/contrib/forms/locale/my/LC_MESSAGES/django.po +1 -1
  270. wagtail/contrib/forms/locale/nb/LC_MESSAGES/django.po +1 -1
  271. wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.mo +0 -0
  272. wagtail/contrib/forms/locale/nl/LC_MESSAGES/django.po +20 -3
  273. wagtail/contrib/forms/locale/pl/LC_MESSAGES/django.po +1 -1
  274. wagtail/contrib/forms/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  275. wagtail/contrib/forms/locale/pt_PT/LC_MESSAGES/django.po +1 -1
  276. wagtail/contrib/forms/locale/ro/LC_MESSAGES/django.po +1 -1
  277. wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.mo +0 -0
  278. wagtail/contrib/forms/locale/ru/LC_MESSAGES/django.po +19 -2
  279. wagtail/contrib/forms/locale/sk_SK/LC_MESSAGES/django.po +1 -1
  280. wagtail/contrib/forms/locale/sl/LC_MESSAGES/django.po +1 -1
  281. wagtail/contrib/forms/locale/sv/LC_MESSAGES/django.po +1 -1
  282. wagtail/contrib/forms/locale/tet/LC_MESSAGES/django.po +1 -1
  283. wagtail/contrib/forms/locale/th/LC_MESSAGES/django.po +1 -1
  284. wagtail/contrib/forms/locale/tr/LC_MESSAGES/django.mo +0 -0
  285. wagtail/contrib/forms/locale/tr/LC_MESSAGES/django.po +12 -2
  286. wagtail/contrib/forms/locale/tr_TR/LC_MESSAGES/django.po +1 -1
  287. wagtail/contrib/forms/locale/ug/LC_MESSAGES/django.po +1 -1
  288. wagtail/contrib/forms/locale/uk/LC_MESSAGES/django.po +1 -1
  289. wagtail/contrib/forms/locale/vi/LC_MESSAGES/django.po +1 -1
  290. wagtail/contrib/forms/locale/zh/LC_MESSAGES/django.po +1 -1
  291. wagtail/contrib/forms/locale/zh_Hans/LC_MESSAGES/django.po +1 -1
  292. wagtail/contrib/forms/locale/zh_Hant/LC_MESSAGES/django.po +1 -1
  293. wagtail/contrib/frontend_cache/tests.py +4 -2
  294. wagtail/contrib/redirects/locale/ar/LC_MESSAGES/django.mo +0 -0
  295. wagtail/contrib/redirects/locale/ar/LC_MESSAGES/django.po +1 -13
  296. wagtail/contrib/redirects/locale/be/LC_MESSAGES/django.po +1 -1
  297. wagtail/contrib/redirects/locale/bg/LC_MESSAGES/django.po +1 -1
  298. wagtail/contrib/redirects/locale/bn/LC_MESSAGES/django.po +1 -1
  299. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.mo +0 -0
  300. wagtail/contrib/redirects/locale/ca/LC_MESSAGES/django.po +9 -10
  301. wagtail/contrib/redirects/locale/cs/LC_MESSAGES/django.mo +0 -0
  302. wagtail/contrib/redirects/locale/cs/LC_MESSAGES/django.po +1 -13
  303. wagtail/contrib/redirects/locale/cy/LC_MESSAGES/django.mo +0 -0
  304. wagtail/contrib/redirects/locale/cy/LC_MESSAGES/django.po +1 -13
  305. wagtail/contrib/redirects/locale/da/LC_MESSAGES/django.po +1 -1
  306. wagtail/contrib/redirects/locale/de/LC_MESSAGES/django.mo +0 -0
  307. wagtail/contrib/redirects/locale/de/LC_MESSAGES/django.po +1 -13
  308. wagtail/contrib/redirects/locale/dv/LC_MESSAGES/django.po +1 -1
  309. wagtail/contrib/redirects/locale/el/LC_MESSAGES/django.po +1 -1
  310. wagtail/contrib/redirects/locale/en/LC_MESSAGES/django.po +4 -4
  311. wagtail/contrib/redirects/locale/en_IN/LC_MESSAGES/django.po +1 -1
  312. wagtail/contrib/redirects/locale/es/LC_MESSAGES/django.mo +0 -0
  313. wagtail/contrib/redirects/locale/es/LC_MESSAGES/django.po +1 -14
  314. wagtail/contrib/redirects/locale/es_419/LC_MESSAGES/django.po +1 -1
  315. wagtail/contrib/redirects/locale/es_VE/LC_MESSAGES/django.po +1 -1
  316. wagtail/contrib/redirects/locale/et/LC_MESSAGES/django.mo +0 -0
  317. wagtail/contrib/redirects/locale/et/LC_MESSAGES/django.po +1 -13
  318. wagtail/contrib/redirects/locale/eu/LC_MESSAGES/django.po +1 -1
  319. wagtail/contrib/redirects/locale/fa/LC_MESSAGES/django.po +1 -1
  320. wagtail/contrib/redirects/locale/fi/LC_MESSAGES/django.mo +0 -0
  321. wagtail/contrib/redirects/locale/fi/LC_MESSAGES/django.po +7 -11
  322. wagtail/contrib/redirects/locale/fr/LC_MESSAGES/django.mo +0 -0
  323. wagtail/contrib/redirects/locale/fr/LC_MESSAGES/django.po +9 -8
  324. wagtail/contrib/redirects/locale/gl/LC_MESSAGES/django.mo +0 -0
  325. wagtail/contrib/redirects/locale/gl/LC_MESSAGES/django.po +9 -9
  326. wagtail/contrib/redirects/locale/he_IL/LC_MESSAGES/django.po +1 -1
  327. wagtail/contrib/redirects/locale/hi/LC_MESSAGES/django.po +1 -1
  328. wagtail/contrib/redirects/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  329. wagtail/contrib/redirects/locale/hr_HR/LC_MESSAGES/django.po +1 -13
  330. wagtail/contrib/redirects/locale/ht/LC_MESSAGES/django.po +1 -1
  331. wagtail/contrib/redirects/locale/hu/LC_MESSAGES/django.mo +0 -0
  332. wagtail/contrib/redirects/locale/hu/LC_MESSAGES/django.po +1 -13
  333. wagtail/contrib/redirects/locale/hy/LC_MESSAGES/django.po +1 -1
  334. wagtail/contrib/redirects/locale/id_ID/LC_MESSAGES/django.po +1 -1
  335. wagtail/contrib/redirects/locale/is_IS/LC_MESSAGES/django.mo +0 -0
  336. wagtail/contrib/redirects/locale/is_IS/LC_MESSAGES/django.po +1 -13
  337. wagtail/contrib/redirects/locale/it/LC_MESSAGES/django.mo +0 -0
  338. wagtail/contrib/redirects/locale/it/LC_MESSAGES/django.po +1 -14
  339. wagtail/contrib/redirects/locale/ja/LC_MESSAGES/django.mo +0 -0
  340. wagtail/contrib/redirects/locale/ja/LC_MESSAGES/django.po +1 -13
  341. wagtail/contrib/redirects/locale/ka/LC_MESSAGES/django.po +1 -1
  342. wagtail/contrib/redirects/locale/ko/LC_MESSAGES/django.po +1 -1
  343. wagtail/contrib/redirects/locale/lt/LC_MESSAGES/django.po +1 -1
  344. wagtail/contrib/redirects/locale/lv/LC_MESSAGES/django.po +1 -1
  345. wagtail/contrib/redirects/locale/mi/LC_MESSAGES/django.po +1 -1
  346. wagtail/contrib/redirects/locale/mn/LC_MESSAGES/django.po +1 -1
  347. wagtail/contrib/redirects/locale/my/LC_MESSAGES/django.po +1 -1
  348. wagtail/contrib/redirects/locale/nb/LC_MESSAGES/django.mo +0 -0
  349. wagtail/contrib/redirects/locale/nb/LC_MESSAGES/django.po +1 -13
  350. wagtail/contrib/redirects/locale/nl/LC_MESSAGES/django.mo +0 -0
  351. wagtail/contrib/redirects/locale/nl/LC_MESSAGES/django.po +9 -9
  352. wagtail/contrib/redirects/locale/pl/LC_MESSAGES/django.mo +0 -0
  353. wagtail/contrib/redirects/locale/pl/LC_MESSAGES/django.po +1 -14
  354. wagtail/contrib/redirects/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  355. wagtail/contrib/redirects/locale/pt_BR/LC_MESSAGES/django.po +1 -13
  356. wagtail/contrib/redirects/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  357. wagtail/contrib/redirects/locale/pt_PT/LC_MESSAGES/django.po +1 -13
  358. wagtail/contrib/redirects/locale/ro/LC_MESSAGES/django.mo +0 -0
  359. wagtail/contrib/redirects/locale/ro/LC_MESSAGES/django.po +1 -13
  360. wagtail/contrib/redirects/locale/ru/LC_MESSAGES/django.mo +0 -0
  361. wagtail/contrib/redirects/locale/ru/LC_MESSAGES/django.po +1 -13
  362. wagtail/contrib/redirects/locale/sk_SK/LC_MESSAGES/django.po +1 -1
  363. wagtail/contrib/redirects/locale/sl/LC_MESSAGES/django.mo +0 -0
  364. wagtail/contrib/redirects/locale/sl/LC_MESSAGES/django.po +1 -14
  365. wagtail/contrib/redirects/locale/sr/LC_MESSAGES/django.po +1 -1
  366. wagtail/contrib/redirects/locale/sv/LC_MESSAGES/django.mo +0 -0
  367. wagtail/contrib/redirects/locale/sv/LC_MESSAGES/django.po +1 -13
  368. wagtail/contrib/redirects/locale/ta/LC_MESSAGES/django.po +1 -1
  369. wagtail/contrib/redirects/locale/tet/LC_MESSAGES/django.po +1 -1
  370. wagtail/contrib/redirects/locale/th/LC_MESSAGES/django.po +1 -1
  371. wagtail/contrib/redirects/locale/tr/LC_MESSAGES/django.mo +0 -0
  372. wagtail/contrib/redirects/locale/tr/LC_MESSAGES/django.po +1 -13
  373. wagtail/contrib/redirects/locale/tr_TR/LC_MESSAGES/django.po +1 -1
  374. wagtail/contrib/redirects/locale/ug/LC_MESSAGES/django.mo +0 -0
  375. wagtail/contrib/redirects/locale/ug/LC_MESSAGES/django.po +1 -13
  376. wagtail/contrib/redirects/locale/uk/LC_MESSAGES/django.mo +0 -0
  377. wagtail/contrib/redirects/locale/uk/LC_MESSAGES/django.po +1 -13
  378. wagtail/contrib/redirects/locale/vi/LC_MESSAGES/django.po +1 -1
  379. wagtail/contrib/redirects/locale/zh/LC_MESSAGES/django.po +1 -1
  380. wagtail/contrib/redirects/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  381. wagtail/contrib/redirects/locale/zh_Hans/LC_MESSAGES/django.po +1 -13
  382. wagtail/contrib/redirects/locale/zh_Hant/LC_MESSAGES/django.po +1 -1
  383. wagtail/contrib/redirects/tests/test_tmp_storages.py +20 -0
  384. wagtail/contrib/redirects/tmp_storages.py +1 -1
  385. wagtail/contrib/redirects/views.py +3 -3
  386. wagtail/contrib/search_promotions/locale/af/LC_MESSAGES/django.po +1 -1
  387. wagtail/contrib/search_promotions/locale/ar/LC_MESSAGES/django.mo +0 -0
  388. wagtail/contrib/search_promotions/locale/ar/LC_MESSAGES/django.po +1 -7
  389. wagtail/contrib/search_promotions/locale/az_AZ/LC_MESSAGES/django.po +1 -1
  390. wagtail/contrib/search_promotions/locale/be/LC_MESSAGES/django.mo +0 -0
  391. wagtail/contrib/search_promotions/locale/be/LC_MESSAGES/django.po +1 -7
  392. wagtail/contrib/search_promotions/locale/bg/LC_MESSAGES/django.po +1 -1
  393. wagtail/contrib/search_promotions/locale/bn/LC_MESSAGES/django.po +1 -1
  394. wagtail/contrib/search_promotions/locale/ca/LC_MESSAGES/django.mo +0 -0
  395. wagtail/contrib/search_promotions/locale/ca/LC_MESSAGES/django.po +5 -5
  396. wagtail/contrib/search_promotions/locale/cs/LC_MESSAGES/django.mo +0 -0
  397. wagtail/contrib/search_promotions/locale/cs/LC_MESSAGES/django.po +1 -7
  398. wagtail/contrib/search_promotions/locale/cy/LC_MESSAGES/django.mo +0 -0
  399. wagtail/contrib/search_promotions/locale/cy/LC_MESSAGES/django.po +1 -7
  400. wagtail/contrib/search_promotions/locale/da/LC_MESSAGES/django.po +1 -1
  401. wagtail/contrib/search_promotions/locale/de/LC_MESSAGES/django.mo +0 -0
  402. wagtail/contrib/search_promotions/locale/de/LC_MESSAGES/django.po +1 -7
  403. wagtail/contrib/search_promotions/locale/dv/LC_MESSAGES/django.po +1 -1
  404. wagtail/contrib/search_promotions/locale/el/LC_MESSAGES/django.mo +0 -0
  405. wagtail/contrib/search_promotions/locale/el/LC_MESSAGES/django.po +1 -7
  406. wagtail/contrib/search_promotions/locale/en/LC_MESSAGES/django.po +3 -3
  407. wagtail/contrib/search_promotions/locale/es/LC_MESSAGES/django.mo +0 -0
  408. wagtail/contrib/search_promotions/locale/es/LC_MESSAGES/django.po +1 -7
  409. wagtail/contrib/search_promotions/locale/es_419/LC_MESSAGES/django.po +1 -1
  410. wagtail/contrib/search_promotions/locale/et/LC_MESSAGES/django.mo +0 -0
  411. wagtail/contrib/search_promotions/locale/et/LC_MESSAGES/django.po +1 -7
  412. wagtail/contrib/search_promotions/locale/eu/LC_MESSAGES/django.po +1 -1
  413. wagtail/contrib/search_promotions/locale/fa/LC_MESSAGES/django.mo +0 -0
  414. wagtail/contrib/search_promotions/locale/fa/LC_MESSAGES/django.po +1 -7
  415. wagtail/contrib/search_promotions/locale/fi/LC_MESSAGES/django.mo +0 -0
  416. wagtail/contrib/search_promotions/locale/fi/LC_MESSAGES/django.po +1 -7
  417. wagtail/contrib/search_promotions/locale/fr/LC_MESSAGES/django.mo +0 -0
  418. wagtail/contrib/search_promotions/locale/fr/LC_MESSAGES/django.po +5 -5
  419. wagtail/contrib/search_promotions/locale/gl/LC_MESSAGES/django.mo +0 -0
  420. wagtail/contrib/search_promotions/locale/gl/LC_MESSAGES/django.po +5 -5
  421. wagtail/contrib/search_promotions/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  422. wagtail/contrib/search_promotions/locale/he_IL/LC_MESSAGES/django.po +1 -7
  423. wagtail/contrib/search_promotions/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  424. wagtail/contrib/search_promotions/locale/hr_HR/LC_MESSAGES/django.po +1 -7
  425. wagtail/contrib/search_promotions/locale/ht/LC_MESSAGES/django.po +1 -1
  426. wagtail/contrib/search_promotions/locale/hu/LC_MESSAGES/django.mo +0 -0
  427. wagtail/contrib/search_promotions/locale/hu/LC_MESSAGES/django.po +1 -7
  428. wagtail/contrib/search_promotions/locale/id_ID/LC_MESSAGES/django.mo +0 -0
  429. wagtail/contrib/search_promotions/locale/id_ID/LC_MESSAGES/django.po +1 -7
  430. wagtail/contrib/search_promotions/locale/is_IS/LC_MESSAGES/django.mo +0 -0
  431. wagtail/contrib/search_promotions/locale/is_IS/LC_MESSAGES/django.po +1 -7
  432. wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.mo +0 -0
  433. wagtail/contrib/search_promotions/locale/it/LC_MESSAGES/django.po +1 -7
  434. wagtail/contrib/search_promotions/locale/ja/LC_MESSAGES/django.mo +0 -0
  435. wagtail/contrib/search_promotions/locale/ja/LC_MESSAGES/django.po +1 -7
  436. wagtail/contrib/search_promotions/locale/ka/LC_MESSAGES/django.po +1 -1
  437. wagtail/contrib/search_promotions/locale/ko/LC_MESSAGES/django.mo +0 -0
  438. wagtail/contrib/search_promotions/locale/ko/LC_MESSAGES/django.po +1 -7
  439. wagtail/contrib/search_promotions/locale/lt/LC_MESSAGES/django.mo +0 -0
  440. wagtail/contrib/search_promotions/locale/lt/LC_MESSAGES/django.po +1 -7
  441. wagtail/contrib/search_promotions/locale/lv/LC_MESSAGES/django.mo +0 -0
  442. wagtail/contrib/search_promotions/locale/lv/LC_MESSAGES/django.po +1 -7
  443. wagtail/contrib/search_promotions/locale/mi/LC_MESSAGES/django.po +1 -1
  444. wagtail/contrib/search_promotions/locale/mn/LC_MESSAGES/django.po +1 -1
  445. wagtail/contrib/search_promotions/locale/my/LC_MESSAGES/django.po +1 -1
  446. wagtail/contrib/search_promotions/locale/nb/LC_MESSAGES/django.mo +0 -0
  447. wagtail/contrib/search_promotions/locale/nb/LC_MESSAGES/django.po +1 -7
  448. wagtail/contrib/search_promotions/locale/nl/LC_MESSAGES/django.mo +0 -0
  449. wagtail/contrib/search_promotions/locale/nl/LC_MESSAGES/django.po +4 -4
  450. wagtail/contrib/search_promotions/locale/pl/LC_MESSAGES/django.mo +0 -0
  451. wagtail/contrib/search_promotions/locale/pl/LC_MESSAGES/django.po +1 -7
  452. wagtail/contrib/search_promotions/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  453. wagtail/contrib/search_promotions/locale/pt_BR/LC_MESSAGES/django.po +1 -7
  454. wagtail/contrib/search_promotions/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  455. wagtail/contrib/search_promotions/locale/pt_PT/LC_MESSAGES/django.po +1 -7
  456. wagtail/contrib/search_promotions/locale/ro/LC_MESSAGES/django.mo +0 -0
  457. wagtail/contrib/search_promotions/locale/ro/LC_MESSAGES/django.po +1 -7
  458. wagtail/contrib/search_promotions/locale/ru/LC_MESSAGES/django.mo +0 -0
  459. wagtail/contrib/search_promotions/locale/ru/LC_MESSAGES/django.po +1 -7
  460. wagtail/contrib/search_promotions/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  461. wagtail/contrib/search_promotions/locale/sk_SK/LC_MESSAGES/django.po +1 -7
  462. wagtail/contrib/search_promotions/locale/sl/LC_MESSAGES/django.mo +0 -0
  463. wagtail/contrib/search_promotions/locale/sl/LC_MESSAGES/django.po +1 -7
  464. wagtail/contrib/search_promotions/locale/sv/LC_MESSAGES/django.mo +0 -0
  465. wagtail/contrib/search_promotions/locale/sv/LC_MESSAGES/django.po +1 -7
  466. wagtail/contrib/search_promotions/locale/tet/LC_MESSAGES/django.mo +0 -0
  467. wagtail/contrib/search_promotions/locale/tet/LC_MESSAGES/django.po +1 -7
  468. wagtail/contrib/search_promotions/locale/th/LC_MESSAGES/django.mo +0 -0
  469. wagtail/contrib/search_promotions/locale/th/LC_MESSAGES/django.po +1 -7
  470. wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.mo +0 -0
  471. wagtail/contrib/search_promotions/locale/tr/LC_MESSAGES/django.po +44 -10
  472. wagtail/contrib/search_promotions/locale/tr_TR/LC_MESSAGES/django.mo +0 -0
  473. wagtail/contrib/search_promotions/locale/tr_TR/LC_MESSAGES/django.po +1 -7
  474. wagtail/contrib/search_promotions/locale/ug/LC_MESSAGES/django.mo +0 -0
  475. wagtail/contrib/search_promotions/locale/ug/LC_MESSAGES/django.po +1 -7
  476. wagtail/contrib/search_promotions/locale/uk/LC_MESSAGES/django.mo +0 -0
  477. wagtail/contrib/search_promotions/locale/uk/LC_MESSAGES/django.po +1 -7
  478. wagtail/contrib/search_promotions/locale/vi/LC_MESSAGES/django.po +1 -1
  479. wagtail/contrib/search_promotions/locale/zh/LC_MESSAGES/django.po +1 -1
  480. wagtail/contrib/search_promotions/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  481. wagtail/contrib/search_promotions/locale/zh_Hans/LC_MESSAGES/django.po +1 -7
  482. wagtail/contrib/search_promotions/locale/zh_Hant/LC_MESSAGES/django.mo +0 -0
  483. wagtail/contrib/search_promotions/locale/zh_Hant/LC_MESSAGES/django.po +1 -7
  484. wagtail/contrib/search_promotions/static/wagtailsearchpromotions/js/query-chooser-modal.js +1 -1
  485. wagtail/contrib/search_promotions/views/settings.py +2 -2
  486. wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.mo +0 -0
  487. wagtail/contrib/settings/locale/cs/LC_MESSAGES/django.po +6 -1
  488. wagtail/contrib/settings/locale/en/LC_MESSAGES/django.po +1 -1
  489. wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.mo +0 -0
  490. wagtail/contrib/settings/locale/nl/LC_MESSAGES/django.po +6 -2
  491. wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.mo +0 -0
  492. wagtail/contrib/settings/locale/ru/LC_MESSAGES/django.po +6 -1
  493. wagtail/contrib/settings/tests/site_specific/test_admin.py +48 -6
  494. wagtail/contrib/simple_translation/locale/en/LC_MESSAGES/django.po +1 -1
  495. wagtail/contrib/styleguide/locale/en/LC_MESSAGES/django.po +1 -1
  496. wagtail/contrib/styleguide/templates/wagtailstyleguide/base.html +5 -5
  497. wagtail/contrib/table_block/blocks.py +1 -0
  498. wagtail/contrib/table_block/locale/ar/LC_MESSAGES/django.po +1 -1
  499. wagtail/contrib/table_block/locale/be/LC_MESSAGES/django.po +1 -1
  500. wagtail/contrib/table_block/locale/ca/LC_MESSAGES/django.mo +0 -0
  501. wagtail/contrib/table_block/locale/ca/LC_MESSAGES/django.po +6 -3
  502. wagtail/contrib/table_block/locale/cs/LC_MESSAGES/django.po +1 -1
  503. wagtail/contrib/table_block/locale/cy/LC_MESSAGES/django.po +1 -1
  504. wagtail/contrib/table_block/locale/de/LC_MESSAGES/django.po +1 -1
  505. wagtail/contrib/table_block/locale/dv/LC_MESSAGES/django.po +1 -1
  506. wagtail/contrib/table_block/locale/el/LC_MESSAGES/django.po +1 -1
  507. wagtail/contrib/table_block/locale/en/LC_MESSAGES/django.po +5 -1
  508. wagtail/contrib/table_block/locale/en_IN/LC_MESSAGES/django.po +1 -1
  509. wagtail/contrib/table_block/locale/es/LC_MESSAGES/django.po +1 -1
  510. wagtail/contrib/table_block/locale/et/LC_MESSAGES/django.po +1 -1
  511. wagtail/contrib/table_block/locale/fa/LC_MESSAGES/django.po +1 -1
  512. wagtail/contrib/table_block/locale/fi/LC_MESSAGES/django.po +1 -1
  513. wagtail/contrib/table_block/locale/fr/LC_MESSAGES/django.mo +0 -0
  514. wagtail/contrib/table_block/locale/fr/LC_MESSAGES/django.po +6 -3
  515. wagtail/contrib/table_block/locale/gl/LC_MESSAGES/django.mo +0 -0
  516. wagtail/contrib/table_block/locale/gl/LC_MESSAGES/django.po +6 -3
  517. wagtail/contrib/table_block/locale/hr_HR/LC_MESSAGES/django.po +1 -1
  518. wagtail/contrib/table_block/locale/ht/LC_MESSAGES/django.po +1 -1
  519. wagtail/contrib/table_block/locale/hu/LC_MESSAGES/django.po +1 -1
  520. wagtail/contrib/table_block/locale/id_ID/LC_MESSAGES/django.po +1 -1
  521. wagtail/contrib/table_block/locale/is_IS/LC_MESSAGES/django.po +1 -1
  522. wagtail/contrib/table_block/locale/it/LC_MESSAGES/django.po +1 -1
  523. wagtail/contrib/table_block/locale/ja/LC_MESSAGES/django.po +1 -1
  524. wagtail/contrib/table_block/locale/ko/LC_MESSAGES/django.po +1 -1
  525. wagtail/contrib/table_block/locale/lt/LC_MESSAGES/django.po +1 -1
  526. wagtail/contrib/table_block/locale/lv/LC_MESSAGES/django.po +1 -1
  527. wagtail/contrib/table_block/locale/mi/LC_MESSAGES/django.po +1 -1
  528. wagtail/contrib/table_block/locale/mn/LC_MESSAGES/django.po +1 -1
  529. wagtail/contrib/table_block/locale/my/LC_MESSAGES/django.po +1 -1
  530. wagtail/contrib/table_block/locale/nb/LC_MESSAGES/django.po +1 -1
  531. wagtail/contrib/table_block/locale/nl/LC_MESSAGES/django.mo +0 -0
  532. wagtail/contrib/table_block/locale/nl/LC_MESSAGES/django.po +6 -3
  533. wagtail/contrib/table_block/locale/pl/LC_MESSAGES/django.po +1 -1
  534. wagtail/contrib/table_block/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  535. wagtail/contrib/table_block/locale/pt_PT/LC_MESSAGES/django.po +1 -1
  536. wagtail/contrib/table_block/locale/ro/LC_MESSAGES/django.po +1 -1
  537. wagtail/contrib/table_block/locale/ru/LC_MESSAGES/django.po +1 -1
  538. wagtail/contrib/table_block/locale/sk_SK/LC_MESSAGES/django.po +1 -1
  539. wagtail/contrib/table_block/locale/sl/LC_MESSAGES/django.po +1 -1
  540. wagtail/contrib/table_block/locale/sv/LC_MESSAGES/django.po +1 -1
  541. wagtail/contrib/table_block/locale/tet/LC_MESSAGES/django.po +1 -1
  542. wagtail/contrib/table_block/locale/th/LC_MESSAGES/django.po +1 -1
  543. wagtail/contrib/table_block/locale/tr/LC_MESSAGES/django.po +1 -1
  544. wagtail/contrib/table_block/locale/tr_TR/LC_MESSAGES/django.po +1 -1
  545. wagtail/contrib/table_block/locale/ug/LC_MESSAGES/django.po +1 -1
  546. wagtail/contrib/table_block/locale/uk/LC_MESSAGES/django.po +1 -1
  547. wagtail/contrib/table_block/locale/vi/LC_MESSAGES/django.po +1 -1
  548. wagtail/contrib/table_block/locale/zh_Hans/LC_MESSAGES/django.po +1 -1
  549. wagtail/contrib/table_block/locale/zh_Hant/LC_MESSAGES/django.po +1 -1
  550. wagtail/contrib/table_block/static/table_block/js/table.js +1 -1
  551. wagtail/contrib/typed_table_block/locale/en/LC_MESSAGES/django.po +1 -1
  552. wagtail/contrib/typed_table_block/static/typed_table_block/js/typed_table_block.js +1 -1
  553. wagtail/coreutils.py +5 -5
  554. wagtail/documents/forms.py +18 -1
  555. wagtail/documents/locale/af/LC_MESSAGES/django.po +1 -1
  556. wagtail/documents/locale/ar/LC_MESSAGES/django.mo +0 -0
  557. wagtail/documents/locale/ar/LC_MESSAGES/django.po +1 -5
  558. wagtail/documents/locale/az_AZ/LC_MESSAGES/django.po +1 -1
  559. wagtail/documents/locale/be/LC_MESSAGES/django.mo +0 -0
  560. wagtail/documents/locale/be/LC_MESSAGES/django.po +1 -5
  561. wagtail/documents/locale/bg/LC_MESSAGES/django.po +1 -1
  562. wagtail/documents/locale/bn/LC_MESSAGES/django.po +1 -1
  563. wagtail/documents/locale/ca/LC_MESSAGES/django.mo +0 -0
  564. wagtail/documents/locale/ca/LC_MESSAGES/django.po +5 -5
  565. wagtail/documents/locale/cs/LC_MESSAGES/django.mo +0 -0
  566. wagtail/documents/locale/cs/LC_MESSAGES/django.po +1 -7
  567. wagtail/documents/locale/cy/LC_MESSAGES/django.po +1 -1
  568. wagtail/documents/locale/da/LC_MESSAGES/django.po +1 -1
  569. wagtail/documents/locale/de/LC_MESSAGES/django.mo +0 -0
  570. wagtail/documents/locale/de/LC_MESSAGES/django.po +1 -7
  571. wagtail/documents/locale/dv/LC_MESSAGES/django.po +1 -1
  572. wagtail/documents/locale/el/LC_MESSAGES/django.mo +0 -0
  573. wagtail/documents/locale/el/LC_MESSAGES/django.po +1 -7
  574. wagtail/documents/locale/en/LC_MESSAGES/django.po +10 -10
  575. wagtail/documents/locale/es/LC_MESSAGES/django.mo +0 -0
  576. wagtail/documents/locale/es/LC_MESSAGES/django.po +1 -7
  577. wagtail/documents/locale/es_419/LC_MESSAGES/django.po +1 -1
  578. wagtail/documents/locale/et/LC_MESSAGES/django.mo +0 -0
  579. wagtail/documents/locale/et/LC_MESSAGES/django.po +1 -5
  580. wagtail/documents/locale/eu/LC_MESSAGES/django.po +1 -1
  581. wagtail/documents/locale/fa/LC_MESSAGES/django.mo +0 -0
  582. wagtail/documents/locale/fa/LC_MESSAGES/django.po +1 -5
  583. wagtail/documents/locale/fi/LC_MESSAGES/django.mo +0 -0
  584. wagtail/documents/locale/fi/LC_MESSAGES/django.po +1 -5
  585. wagtail/documents/locale/fr/LC_MESSAGES/django.mo +0 -0
  586. wagtail/documents/locale/fr/LC_MESSAGES/django.po +5 -5
  587. wagtail/documents/locale/gl/LC_MESSAGES/django.mo +0 -0
  588. wagtail/documents/locale/gl/LC_MESSAGES/django.po +5 -5
  589. wagtail/documents/locale/he_IL/LC_MESSAGES/django.mo +0 -0
  590. wagtail/documents/locale/he_IL/LC_MESSAGES/django.po +1 -5
  591. wagtail/documents/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  592. wagtail/documents/locale/hr_HR/LC_MESSAGES/django.po +1 -6
  593. wagtail/documents/locale/ht/LC_MESSAGES/django.po +1 -1
  594. wagtail/documents/locale/hu/LC_MESSAGES/django.mo +0 -0
  595. wagtail/documents/locale/hu/LC_MESSAGES/django.po +1 -7
  596. wagtail/documents/locale/id_ID/LC_MESSAGES/django.mo +0 -0
  597. wagtail/documents/locale/id_ID/LC_MESSAGES/django.po +1 -6
  598. wagtail/documents/locale/is_IS/LC_MESSAGES/django.mo +0 -0
  599. wagtail/documents/locale/is_IS/LC_MESSAGES/django.po +1 -5
  600. wagtail/documents/locale/it/LC_MESSAGES/django.mo +0 -0
  601. wagtail/documents/locale/it/LC_MESSAGES/django.po +1 -5
  602. wagtail/documents/locale/ja/LC_MESSAGES/django.mo +0 -0
  603. wagtail/documents/locale/ja/LC_MESSAGES/django.po +1 -7
  604. wagtail/documents/locale/ka/LC_MESSAGES/django.po +1 -1
  605. wagtail/documents/locale/ko/LC_MESSAGES/django.mo +0 -0
  606. wagtail/documents/locale/ko/LC_MESSAGES/django.po +1 -6
  607. wagtail/documents/locale/lt/LC_MESSAGES/django.mo +0 -0
  608. wagtail/documents/locale/lt/LC_MESSAGES/django.po +1 -5
  609. wagtail/documents/locale/lv/LC_MESSAGES/django.po +1 -1
  610. wagtail/documents/locale/mi/LC_MESSAGES/django.mo +0 -0
  611. wagtail/documents/locale/mi/LC_MESSAGES/django.po +1 -7
  612. wagtail/documents/locale/mn/LC_MESSAGES/django.mo +0 -0
  613. wagtail/documents/locale/mn/LC_MESSAGES/django.po +1 -5
  614. wagtail/documents/locale/my/LC_MESSAGES/django.po +1 -1
  615. wagtail/documents/locale/nb/LC_MESSAGES/django.mo +0 -0
  616. wagtail/documents/locale/nb/LC_MESSAGES/django.po +1 -5
  617. wagtail/documents/locale/nl/LC_MESSAGES/django.mo +0 -0
  618. wagtail/documents/locale/nl/LC_MESSAGES/django.po +15 -6
  619. wagtail/documents/locale/pl/LC_MESSAGES/django.mo +0 -0
  620. wagtail/documents/locale/pl/LC_MESSAGES/django.po +1 -6
  621. wagtail/documents/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  622. wagtail/documents/locale/pt_BR/LC_MESSAGES/django.po +1 -7
  623. wagtail/documents/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  624. wagtail/documents/locale/pt_PT/LC_MESSAGES/django.po +1 -6
  625. wagtail/documents/locale/ro/LC_MESSAGES/django.mo +0 -0
  626. wagtail/documents/locale/ro/LC_MESSAGES/django.po +1 -5
  627. wagtail/documents/locale/ru/LC_MESSAGES/django.mo +0 -0
  628. wagtail/documents/locale/ru/LC_MESSAGES/django.po +10 -7
  629. wagtail/documents/locale/sk_SK/LC_MESSAGES/django.mo +0 -0
  630. wagtail/documents/locale/sk_SK/LC_MESSAGES/django.po +1 -5
  631. wagtail/documents/locale/sl/LC_MESSAGES/django.mo +0 -0
  632. wagtail/documents/locale/sl/LC_MESSAGES/django.po +1 -7
  633. wagtail/documents/locale/sv/LC_MESSAGES/django.mo +0 -0
  634. wagtail/documents/locale/sv/LC_MESSAGES/django.po +1 -6
  635. wagtail/documents/locale/tet/LC_MESSAGES/django.po +1 -1
  636. wagtail/documents/locale/th/LC_MESSAGES/django.mo +0 -0
  637. wagtail/documents/locale/th/LC_MESSAGES/django.po +1 -5
  638. wagtail/documents/locale/tr/LC_MESSAGES/django.mo +0 -0
  639. wagtail/documents/locale/tr/LC_MESSAGES/django.po +13 -5
  640. wagtail/documents/locale/tr_TR/LC_MESSAGES/django.mo +0 -0
  641. wagtail/documents/locale/tr_TR/LC_MESSAGES/django.po +1 -5
  642. wagtail/documents/locale/ug/LC_MESSAGES/django.mo +0 -0
  643. wagtail/documents/locale/ug/LC_MESSAGES/django.po +1 -5
  644. wagtail/documents/locale/uk/LC_MESSAGES/django.mo +0 -0
  645. wagtail/documents/locale/uk/LC_MESSAGES/django.po +1 -5
  646. wagtail/documents/locale/vi/LC_MESSAGES/django.po +1 -1
  647. wagtail/documents/locale/zh/LC_MESSAGES/django.po +1 -1
  648. wagtail/documents/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  649. wagtail/documents/locale/zh_Hans/LC_MESSAGES/django.po +1 -5
  650. wagtail/documents/locale/zh_Hant/LC_MESSAGES/django.mo +0 -0
  651. wagtail/documents/locale/zh_Hant/LC_MESSAGES/django.po +1 -5
  652. wagtail/documents/models.py +1 -1
  653. wagtail/documents/static/wagtaildocs/js/add-multiple.js +1 -1
  654. wagtail/documents/static/wagtaildocs/js/document-chooser-modal.js +1 -1
  655. wagtail/documents/static/wagtaildocs/js/document-chooser-telepath.js +1 -1
  656. wagtail/documents/static/wagtaildocs/js/document-chooser.js +1 -1
  657. wagtail/documents/templates/wagtaildocs/documents/add.html +0 -34
  658. wagtail/documents/tests/test_admin_views.py +132 -26
  659. wagtail/documents/tests/test_collection_privacy.py +18 -4
  660. wagtail/documents/tests/test_form_overrides.py +1 -1
  661. wagtail/documents/tests/test_search.py +21 -8
  662. wagtail/documents/views/documents.py +1 -1
  663. wagtail/embeds/locale/en/LC_MESSAGES/django.po +1 -1
  664. wagtail/embeds/static/wagtailembeds/js/embed-chooser-modal.js +1 -1
  665. wagtail/images/forms.py +16 -1
  666. wagtail/images/locale/ar/LC_MESSAGES/django.mo +0 -0
  667. wagtail/images/locale/ar/LC_MESSAGES/django.po +7 -10
  668. wagtail/images/locale/az_AZ/LC_MESSAGES/django.po +1 -1
  669. wagtail/images/locale/be/LC_MESSAGES/django.po +7 -7
  670. wagtail/images/locale/bg/LC_MESSAGES/django.po +4 -4
  671. wagtail/images/locale/bn/LC_MESSAGES/django.po +1 -1
  672. wagtail/images/locale/ca/LC_MESSAGES/django.mo +0 -0
  673. wagtail/images/locale/ca/LC_MESSAGES/django.po +15 -9
  674. wagtail/images/locale/cs/LC_MESSAGES/django.mo +0 -0
  675. wagtail/images/locale/cs/LC_MESSAGES/django.po +19 -8
  676. wagtail/images/locale/cy/LC_MESSAGES/django.po +4 -4
  677. wagtail/images/locale/da/LC_MESSAGES/django.po +1 -1
  678. wagtail/images/locale/de/LC_MESSAGES/django.po +7 -7
  679. wagtail/images/locale/dv/LC_MESSAGES/django.po +7 -7
  680. wagtail/images/locale/el/LC_MESSAGES/django.po +7 -7
  681. wagtail/images/locale/en/LC_MESSAGES/django.po +57 -46
  682. wagtail/images/locale/es/LC_MESSAGES/django.po +7 -7
  683. wagtail/images/locale/es_419/LC_MESSAGES/django.po +1 -1
  684. wagtail/images/locale/et/LC_MESSAGES/django.po +7 -7
  685. wagtail/images/locale/eu/LC_MESSAGES/django.po +1 -1
  686. wagtail/images/locale/fa/LC_MESSAGES/django.po +4 -4
  687. wagtail/images/locale/fi/LC_MESSAGES/django.mo +0 -0
  688. wagtail/images/locale/fi/LC_MESSAGES/django.po +18 -9
  689. wagtail/images/locale/fr/LC_MESSAGES/django.mo +0 -0
  690. wagtail/images/locale/fr/LC_MESSAGES/django.po +15 -9
  691. wagtail/images/locale/gl/LC_MESSAGES/django.mo +0 -0
  692. wagtail/images/locale/gl/LC_MESSAGES/django.po +15 -9
  693. wagtail/images/locale/he_IL/LC_MESSAGES/django.po +4 -4
  694. wagtail/images/locale/hr_HR/LC_MESSAGES/django.po +7 -7
  695. wagtail/images/locale/ht/LC_MESSAGES/django.po +1 -1
  696. wagtail/images/locale/hu/LC_MESSAGES/django.mo +0 -0
  697. wagtail/images/locale/hu/LC_MESSAGES/django.po +7 -10
  698. wagtail/images/locale/id_ID/LC_MESSAGES/django.po +4 -4
  699. wagtail/images/locale/is_IS/LC_MESSAGES/django.po +7 -7
  700. wagtail/images/locale/it/LC_MESSAGES/django.po +7 -7
  701. wagtail/images/locale/ja/LC_MESSAGES/django.po +7 -7
  702. wagtail/images/locale/ka/LC_MESSAGES/django.po +4 -4
  703. wagtail/images/locale/ko/LC_MESSAGES/django.po +7 -7
  704. wagtail/images/locale/lt/LC_MESSAGES/django.po +7 -7
  705. wagtail/images/locale/lv/LC_MESSAGES/django.po +4 -4
  706. wagtail/images/locale/mi/LC_MESSAGES/django.po +7 -7
  707. wagtail/images/locale/mn/LC_MESSAGES/django.po +4 -4
  708. wagtail/images/locale/my/LC_MESSAGES/django.po +1 -1
  709. wagtail/images/locale/nb/LC_MESSAGES/django.po +7 -7
  710. wagtail/images/locale/nl/LC_MESSAGES/django.mo +0 -0
  711. wagtail/images/locale/nl/LC_MESSAGES/django.po +50 -21
  712. wagtail/images/locale/pl/LC_MESSAGES/django.po +7 -7
  713. wagtail/images/locale/pt_BR/LC_MESSAGES/django.po +7 -7
  714. wagtail/images/locale/pt_PT/LC_MESSAGES/django.po +7 -7
  715. wagtail/images/locale/ro/LC_MESSAGES/django.po +7 -7
  716. wagtail/images/locale/ru/LC_MESSAGES/django.mo +0 -0
  717. wagtail/images/locale/ru/LC_MESSAGES/django.po +24 -8
  718. wagtail/images/locale/sk_SK/LC_MESSAGES/django.po +4 -4
  719. wagtail/images/locale/sl/LC_MESSAGES/django.po +7 -7
  720. wagtail/images/locale/sv/LC_MESSAGES/django.po +7 -7
  721. wagtail/images/locale/tet/LC_MESSAGES/django.po +4 -4
  722. wagtail/images/locale/th/LC_MESSAGES/django.po +4 -4
  723. wagtail/images/locale/tr/LC_MESSAGES/django.mo +0 -0
  724. wagtail/images/locale/tr/LC_MESSAGES/django.po +85 -7
  725. wagtail/images/locale/tr_TR/LC_MESSAGES/django.po +4 -4
  726. wagtail/images/locale/ug/LC_MESSAGES/django.po +7 -7
  727. wagtail/images/locale/uk/LC_MESSAGES/django.po +7 -7
  728. wagtail/images/locale/vi/LC_MESSAGES/django.po +4 -4
  729. wagtail/images/locale/zh/LC_MESSAGES/django.po +4 -4
  730. wagtail/images/locale/zh_Hans/LC_MESSAGES/django.po +7 -7
  731. wagtail/images/locale/zh_Hant/LC_MESSAGES/django.po +7 -7
  732. wagtail/images/models.py +1 -1
  733. wagtail/images/static/wagtailimages/js/add-multiple.js +1 -1
  734. wagtail/images/static/wagtailimages/js/focal-point-chooser.js +1 -1
  735. wagtail/images/static/wagtailimages/js/image-block.js +1 -1
  736. wagtail/images/static/wagtailimages/js/image-chooser-modal.js +1 -1
  737. wagtail/images/static/wagtailimages/js/image-chooser-telepath.js +1 -1
  738. wagtail/images/static/wagtailimages/js/image-chooser.js +1 -1
  739. wagtail/images/static/wagtailimages/js/image-url-generator.js +1 -1
  740. wagtail/images/static/wagtailimages/js/vendor/jquery.Jcrop.min.js +1 -1
  741. wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-image.js +1 -1
  742. wagtail/images/static/wagtailimages/js/vendor/jquery.fileupload-validate.js +1 -1
  743. wagtail/images/static/wagtailimages/js/vendor/load-image.min.js +1 -1
  744. wagtail/images/templates/wagtailimages/chooser/chooser.html +22 -13
  745. wagtail/images/templates/wagtailimages/chooser/image_preview_column_cell.html +10 -0
  746. wagtail/images/templates/wagtailimages/chooser/results.html +24 -20
  747. wagtail/images/templates/wagtailimages/chooser/title_column_cell.html +15 -0
  748. wagtail/images/templates/wagtailimages/images/add.html +0 -34
  749. wagtail/images/templates/wagtailimages/images/index.html +3 -3
  750. wagtail/images/templates/wagtailimages/images/index_results.html +1 -1
  751. wagtail/images/templates/wagtailimages/images/layout_toggle_button.html +8 -7
  752. wagtail/images/templatetags/wagtailimages_tags.py +2 -2
  753. wagtail/images/tests/test_admin_views.py +87 -0
  754. wagtail/images/tests/test_form_overrides.py +1 -1
  755. wagtail/images/tests/test_models.py +48 -9
  756. wagtail/images/views/chooser.py +66 -2
  757. wagtail/locale/af/LC_MESSAGES/django.po +1 -1
  758. wagtail/locale/ar/LC_MESSAGES/django.mo +0 -0
  759. wagtail/locale/ar/LC_MESSAGES/django.po +1 -9
  760. wagtail/locale/az_AZ/LC_MESSAGES/django.po +1 -1
  761. wagtail/locale/be/LC_MESSAGES/django.po +1 -1
  762. wagtail/locale/bg/LC_MESSAGES/django.po +1 -1
  763. wagtail/locale/bn/LC_MESSAGES/django.po +1 -1
  764. wagtail/locale/ca/LC_MESSAGES/django.mo +0 -0
  765. wagtail/locale/ca/LC_MESSAGES/django.po +4 -4
  766. wagtail/locale/cs/LC_MESSAGES/django.po +1 -1
  767. wagtail/locale/cy/LC_MESSAGES/django.po +1 -1
  768. wagtail/locale/da/LC_MESSAGES/django.po +1 -1
  769. wagtail/locale/de/LC_MESSAGES/django.mo +0 -0
  770. wagtail/locale/de/LC_MESSAGES/django.po +1 -9
  771. wagtail/locale/dv/LC_MESSAGES/django.mo +0 -0
  772. wagtail/locale/dv/LC_MESSAGES/django.po +1 -8
  773. wagtail/locale/el/LC_MESSAGES/django.po +1 -1
  774. wagtail/locale/en/LC_MESSAGES/django.po +55 -55
  775. wagtail/locale/es/LC_MESSAGES/django.po +1 -1
  776. wagtail/locale/es_419/LC_MESSAGES/django.po +1 -1
  777. wagtail/locale/et/LC_MESSAGES/django.po +1 -1
  778. wagtail/locale/eu/LC_MESSAGES/django.po +1 -1
  779. wagtail/locale/fa/LC_MESSAGES/django.po +1 -1
  780. wagtail/locale/fi/LC_MESSAGES/django.po +1 -1
  781. wagtail/locale/fr/LC_MESSAGES/django.mo +0 -0
  782. wagtail/locale/fr/LC_MESSAGES/django.po +4 -4
  783. wagtail/locale/gl/LC_MESSAGES/django.mo +0 -0
  784. wagtail/locale/gl/LC_MESSAGES/django.po +3 -3
  785. wagtail/locale/he_IL/LC_MESSAGES/django.po +1 -1
  786. wagtail/locale/hr_HR/LC_MESSAGES/django.po +1 -1
  787. wagtail/locale/hu/LC_MESSAGES/django.mo +0 -0
  788. wagtail/locale/hu/LC_MESSAGES/django.po +1 -9
  789. wagtail/locale/id_ID/LC_MESSAGES/django.po +1 -1
  790. wagtail/locale/is_IS/LC_MESSAGES/django.mo +0 -0
  791. wagtail/locale/is_IS/LC_MESSAGES/django.po +4 -12
  792. wagtail/locale/it/LC_MESSAGES/django.po +1 -1
  793. wagtail/locale/ja/LC_MESSAGES/django.po +1 -1
  794. wagtail/locale/ka/LC_MESSAGES/django.po +1 -1
  795. wagtail/locale/ko/LC_MESSAGES/django.po +1 -1
  796. wagtail/locale/lt/LC_MESSAGES/django.po +1 -1
  797. wagtail/locale/lv/LC_MESSAGES/django.po +1 -1
  798. wagtail/locale/mi/LC_MESSAGES/django.po +1 -1
  799. wagtail/locale/mn/LC_MESSAGES/django.po +1 -1
  800. wagtail/locale/my/LC_MESSAGES/django.po +1 -1
  801. wagtail/locale/nb/LC_MESSAGES/django.po +1 -1
  802. wagtail/locale/nl/LC_MESSAGES/django.mo +0 -0
  803. wagtail/locale/nl/LC_MESSAGES/django.po +15 -6
  804. wagtail/locale/pl/LC_MESSAGES/django.mo +0 -0
  805. wagtail/locale/pl/LC_MESSAGES/django.po +1 -9
  806. wagtail/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  807. wagtail/locale/pt_PT/LC_MESSAGES/django.po +1 -1
  808. wagtail/locale/ro/LC_MESSAGES/django.mo +0 -0
  809. wagtail/locale/ro/LC_MESSAGES/django.po +1 -9
  810. wagtail/locale/ru/LC_MESSAGES/django.mo +0 -0
  811. wagtail/locale/ru/LC_MESSAGES/django.po +12 -10
  812. wagtail/locale/sk_SK/LC_MESSAGES/django.po +1 -1
  813. wagtail/locale/sl/LC_MESSAGES/django.mo +0 -0
  814. wagtail/locale/sl/LC_MESSAGES/django.po +1 -9
  815. wagtail/locale/sv/LC_MESSAGES/django.mo +0 -0
  816. wagtail/locale/sv/LC_MESSAGES/django.po +1 -9
  817. wagtail/locale/tet/LC_MESSAGES/django.po +1 -1
  818. wagtail/locale/th/LC_MESSAGES/django.po +1 -1
  819. wagtail/locale/tr/LC_MESSAGES/django.mo +0 -0
  820. wagtail/locale/tr/LC_MESSAGES/django.po +4 -8
  821. wagtail/locale/tr_TR/LC_MESSAGES/django.po +1 -1
  822. wagtail/locale/ug/LC_MESSAGES/django.mo +0 -0
  823. wagtail/locale/ug/LC_MESSAGES/django.po +1 -8
  824. wagtail/locale/uk/LC_MESSAGES/django.po +1 -1
  825. wagtail/locale/vi/LC_MESSAGES/django.po +1 -1
  826. wagtail/locale/zh/LC_MESSAGES/django.po +1 -1
  827. wagtail/locale/zh_Hans/LC_MESSAGES/django.po +1 -1
  828. wagtail/locale/zh_Hant/LC_MESSAGES/django.po +1 -1
  829. wagtail/locales/locale/en/LC_MESSAGES/django.po +1 -1
  830. wagtail/locales/locale/nl/LC_MESSAGES/django.mo +0 -0
  831. wagtail/locales/locale/nl/LC_MESSAGES/django.po +12 -1
  832. wagtail/locales/locale/ru/LC_MESSAGES/django.mo +0 -0
  833. wagtail/locales/locale/ru/LC_MESSAGES/django.po +10 -1
  834. wagtail/locales/views.py +2 -2
  835. wagtail/models/orderable.py +10 -0
  836. wagtail/models/pages.py +9 -11
  837. wagtail/models/sites.py +1 -1
  838. wagtail/models/workflows.py +8 -5
  839. wagtail/project_template/home/tests.py +6 -7
  840. wagtail/project_template/project_name/settings/base.py +9 -9
  841. wagtail/project_template/requirements.txt +1 -1
  842. wagtail/query.py +7 -2
  843. wagtail/rich_text/rewriters.py +1 -1
  844. wagtail/search/apps.py +4 -49
  845. wagtail/search/backends/__init__.py +1 -113
  846. wagtail/search/backends/base.py +1 -547
  847. wagtail/search/backends/database/__init__.py +1 -50
  848. wagtail/search/backends/database/fallback.py +1 -253
  849. wagtail/search/backends/database/mysql/mysql.py +1 -700
  850. wagtail/search/backends/database/mysql/query.py +1 -258
  851. wagtail/search/backends/database/postgres/postgres.py +1 -749
  852. wagtail/search/backends/database/postgres/query.py +1 -83
  853. wagtail/search/backends/database/postgres/weights.py +1 -63
  854. wagtail/search/backends/database/sqlite/query.py +1 -294
  855. wagtail/search/backends/database/sqlite/sqlite.py +1 -719
  856. wagtail/search/backends/database/sqlite/utils.py +1 -35
  857. wagtail/search/backends/deprecation.py +45 -0
  858. wagtail/search/backends/elasticsearch7.py +18 -1260
  859. wagtail/search/backends/elasticsearch8.py +21 -96
  860. wagtail/search/backends/elasticsearch9.py +35 -0
  861. wagtail/search/backends/opensearch2.py +35 -0
  862. wagtail/search/backends/opensearch3.py +35 -0
  863. wagtail/search/index.py +1 -358
  864. wagtail/search/locale/ar/LC_MESSAGES/django.mo +0 -0
  865. wagtail/search/locale/ar/LC_MESSAGES/django.po +1 -7
  866. wagtail/search/locale/be/LC_MESSAGES/django.mo +0 -0
  867. wagtail/search/locale/be/LC_MESSAGES/django.po +1 -7
  868. wagtail/search/locale/ca/LC_MESSAGES/django.mo +0 -0
  869. wagtail/search/locale/ca/LC_MESSAGES/django.po +1 -7
  870. wagtail/search/locale/cs/LC_MESSAGES/django.po +1 -1
  871. wagtail/search/locale/cy/LC_MESSAGES/django.mo +0 -0
  872. wagtail/search/locale/cy/LC_MESSAGES/django.po +1 -7
  873. wagtail/search/locale/de/LC_MESSAGES/django.mo +0 -0
  874. wagtail/search/locale/de/LC_MESSAGES/django.po +1 -7
  875. wagtail/search/locale/dv/LC_MESSAGES/django.mo +0 -0
  876. wagtail/search/locale/dv/LC_MESSAGES/django.po +1 -7
  877. wagtail/search/locale/en/LC_MESSAGES/django.po +2 -10
  878. wagtail/search/locale/es/LC_MESSAGES/django.mo +0 -0
  879. wagtail/search/locale/es/LC_MESSAGES/django.po +1 -7
  880. wagtail/search/locale/et/LC_MESSAGES/django.po +1 -1
  881. wagtail/search/locale/fa/LC_MESSAGES/django.po +1 -1
  882. wagtail/search/locale/fi/LC_MESSAGES/django.mo +0 -0
  883. wagtail/search/locale/fi/LC_MESSAGES/django.po +1 -7
  884. wagtail/search/locale/fr/LC_MESSAGES/django.mo +0 -0
  885. wagtail/search/locale/fr/LC_MESSAGES/django.po +1 -7
  886. wagtail/search/locale/gl/LC_MESSAGES/django.mo +0 -0
  887. wagtail/search/locale/gl/LC_MESSAGES/django.po +1 -7
  888. wagtail/search/locale/hr_HR/LC_MESSAGES/django.mo +0 -0
  889. wagtail/search/locale/hr_HR/LC_MESSAGES/django.po +1 -7
  890. wagtail/search/locale/ht/LC_MESSAGES/django.po +1 -1
  891. wagtail/search/locale/hu/LC_MESSAGES/django.mo +0 -0
  892. wagtail/search/locale/hu/LC_MESSAGES/django.po +1 -7
  893. wagtail/search/locale/id_ID/LC_MESSAGES/django.po +1 -1
  894. wagtail/search/locale/is_IS/LC_MESSAGES/django.mo +0 -0
  895. wagtail/search/locale/is_IS/LC_MESSAGES/django.po +1 -7
  896. wagtail/search/locale/it/LC_MESSAGES/django.mo +0 -0
  897. wagtail/search/locale/it/LC_MESSAGES/django.po +1 -7
  898. wagtail/search/locale/ja/LC_MESSAGES/django.po +1 -1
  899. wagtail/search/locale/ko/LC_MESSAGES/django.mo +0 -0
  900. wagtail/search/locale/ko/LC_MESSAGES/django.po +1 -7
  901. wagtail/search/locale/lt/LC_MESSAGES/django.po +1 -1
  902. wagtail/search/locale/mi/LC_MESSAGES/django.po +1 -1
  903. wagtail/search/locale/mn/LC_MESSAGES/django.po +1 -1
  904. wagtail/search/locale/my/LC_MESSAGES/django.po +1 -1
  905. wagtail/search/locale/nb/LC_MESSAGES/django.mo +0 -0
  906. wagtail/search/locale/nb/LC_MESSAGES/django.po +1 -7
  907. wagtail/search/locale/nl/LC_MESSAGES/django.mo +0 -0
  908. wagtail/search/locale/nl/LC_MESSAGES/django.po +1 -7
  909. wagtail/search/locale/pl/LC_MESSAGES/django.mo +0 -0
  910. wagtail/search/locale/pl/LC_MESSAGES/django.po +1 -7
  911. wagtail/search/locale/pt_BR/LC_MESSAGES/django.mo +0 -0
  912. wagtail/search/locale/pt_BR/LC_MESSAGES/django.po +1 -7
  913. wagtail/search/locale/pt_PT/LC_MESSAGES/django.mo +0 -0
  914. wagtail/search/locale/pt_PT/LC_MESSAGES/django.po +1 -7
  915. wagtail/search/locale/ro/LC_MESSAGES/django.mo +0 -0
  916. wagtail/search/locale/ro/LC_MESSAGES/django.po +1 -7
  917. wagtail/search/locale/ru/LC_MESSAGES/django.mo +0 -0
  918. wagtail/search/locale/ru/LC_MESSAGES/django.po +1 -7
  919. wagtail/search/locale/sl/LC_MESSAGES/django.mo +0 -0
  920. wagtail/search/locale/sl/LC_MESSAGES/django.po +1 -7
  921. wagtail/search/locale/sv/LC_MESSAGES/django.mo +0 -0
  922. wagtail/search/locale/sv/LC_MESSAGES/django.po +1 -7
  923. wagtail/search/locale/tet/LC_MESSAGES/django.po +1 -1
  924. wagtail/search/locale/th/LC_MESSAGES/django.po +1 -1
  925. wagtail/search/locale/tr/LC_MESSAGES/django.mo +0 -0
  926. wagtail/search/locale/tr/LC_MESSAGES/django.po +1 -7
  927. wagtail/search/locale/tr_TR/LC_MESSAGES/django.po +1 -1
  928. wagtail/search/locale/ug/LC_MESSAGES/django.mo +0 -0
  929. wagtail/search/locale/ug/LC_MESSAGES/django.po +1 -7
  930. wagtail/search/locale/uk/LC_MESSAGES/django.mo +0 -0
  931. wagtail/search/locale/uk/LC_MESSAGES/django.po +1 -7
  932. wagtail/search/locale/vi/LC_MESSAGES/django.po +1 -1
  933. wagtail/search/locale/zh_Hans/LC_MESSAGES/django.mo +0 -0
  934. wagtail/search/locale/zh_Hans/LC_MESSAGES/django.po +1 -7
  935. wagtail/search/locale/zh_Hant/LC_MESSAGES/django.po +1 -1
  936. wagtail/search/management/commands/update_index.py +1 -205
  937. wagtail/search/management/commands/wagtail_update_index.py +1 -4
  938. wagtail/search/models.py +29 -158
  939. wagtail/search/query.py +1 -114
  940. wagtail/search/queryset.py +1 -43
  941. wagtail/search/signal_handlers.py +1 -24
  942. wagtail/search/tasks.py +1 -10
  943. wagtail/search/tests/test_elasticsearch.py +22 -0
  944. wagtail/search/utils.py +1 -206
  945. wagtail/sites/locale/en/LC_MESSAGES/django.po +1 -1
  946. wagtail/snippets/locale/af/LC_MESSAGES/django.po +1 -1
  947. wagtail/snippets/locale/ar/LC_MESSAGES/django.po +1 -1
  948. wagtail/snippets/locale/az_AZ/LC_MESSAGES/django.po +1 -1
  949. wagtail/snippets/locale/be/LC_MESSAGES/django.po +1 -1
  950. wagtail/snippets/locale/bg/LC_MESSAGES/django.po +1 -1
  951. wagtail/snippets/locale/bn/LC_MESSAGES/django.po +1 -1
  952. wagtail/snippets/locale/ca/LC_MESSAGES/django.po +1 -1
  953. wagtail/snippets/locale/cs/LC_MESSAGES/django.po +1 -1
  954. wagtail/snippets/locale/cy/LC_MESSAGES/django.po +1 -1
  955. wagtail/snippets/locale/da/LC_MESSAGES/django.po +1 -1
  956. wagtail/snippets/locale/de/LC_MESSAGES/django.po +1 -1
  957. wagtail/snippets/locale/dv/LC_MESSAGES/django.po +1 -1
  958. wagtail/snippets/locale/el/LC_MESSAGES/django.po +1 -1
  959. wagtail/snippets/locale/en/LC_MESSAGES/django.po +3 -3
  960. wagtail/snippets/locale/en_IN/LC_MESSAGES/django.po +1 -1
  961. wagtail/snippets/locale/es/LC_MESSAGES/django.po +1 -1
  962. wagtail/snippets/locale/es_419/LC_MESSAGES/django.po +1 -1
  963. wagtail/snippets/locale/es_VE/LC_MESSAGES/django.po +1 -1
  964. wagtail/snippets/locale/et/LC_MESSAGES/django.po +1 -1
  965. wagtail/snippets/locale/eu/LC_MESSAGES/django.po +1 -1
  966. wagtail/snippets/locale/fa/LC_MESSAGES/django.po +1 -1
  967. wagtail/snippets/locale/fi/LC_MESSAGES/django.po +1 -1
  968. wagtail/snippets/locale/fr/LC_MESSAGES/django.po +1 -1
  969. wagtail/snippets/locale/gl/LC_MESSAGES/django.po +1 -1
  970. wagtail/snippets/locale/he_IL/LC_MESSAGES/django.po +1 -1
  971. wagtail/snippets/locale/hi/LC_MESSAGES/django.po +1 -1
  972. wagtail/snippets/locale/hr_HR/LC_MESSAGES/django.po +1 -1
  973. wagtail/snippets/locale/ht/LC_MESSAGES/django.po +1 -1
  974. wagtail/snippets/locale/hu/LC_MESSAGES/django.po +1 -1
  975. wagtail/snippets/locale/id_ID/LC_MESSAGES/django.po +1 -1
  976. wagtail/snippets/locale/is_IS/LC_MESSAGES/django.po +1 -1
  977. wagtail/snippets/locale/it/LC_MESSAGES/django.po +1 -1
  978. wagtail/snippets/locale/ja/LC_MESSAGES/django.po +1 -1
  979. wagtail/snippets/locale/ka/LC_MESSAGES/django.po +1 -1
  980. wagtail/snippets/locale/ko/LC_MESSAGES/django.po +1 -1
  981. wagtail/snippets/locale/lt/LC_MESSAGES/django.po +1 -1
  982. wagtail/snippets/locale/lv/LC_MESSAGES/django.po +1 -1
  983. wagtail/snippets/locale/mi/LC_MESSAGES/django.po +1 -1
  984. wagtail/snippets/locale/mn/LC_MESSAGES/django.po +1 -1
  985. wagtail/snippets/locale/my/LC_MESSAGES/django.po +1 -1
  986. wagtail/snippets/locale/nb/LC_MESSAGES/django.po +1 -1
  987. wagtail/snippets/locale/nl/LC_MESSAGES/django.po +1 -1
  988. wagtail/snippets/locale/pl/LC_MESSAGES/django.po +1 -1
  989. wagtail/snippets/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  990. wagtail/snippets/locale/pt_PT/LC_MESSAGES/django.po +1 -1
  991. wagtail/snippets/locale/ro/LC_MESSAGES/django.po +1 -1
  992. wagtail/snippets/locale/ru/LC_MESSAGES/django.mo +0 -0
  993. wagtail/snippets/locale/ru/LC_MESSAGES/django.po +9 -2
  994. wagtail/snippets/locale/sk_SK/LC_MESSAGES/django.po +1 -1
  995. wagtail/snippets/locale/sl/LC_MESSAGES/django.po +1 -1
  996. wagtail/snippets/locale/sr/LC_MESSAGES/django.po +1 -1
  997. wagtail/snippets/locale/sv/LC_MESSAGES/django.po +1 -1
  998. wagtail/snippets/locale/ta/LC_MESSAGES/django.po +1 -1
  999. wagtail/snippets/locale/tet/LC_MESSAGES/django.po +1 -1
  1000. wagtail/snippets/locale/th/LC_MESSAGES/django.po +1 -1
  1001. wagtail/snippets/locale/tr/LC_MESSAGES/django.mo +0 -0
  1002. wagtail/snippets/locale/tr/LC_MESSAGES/django.po +9 -2
  1003. wagtail/snippets/locale/tr_TR/LC_MESSAGES/django.po +1 -1
  1004. wagtail/snippets/locale/ug/LC_MESSAGES/django.po +1 -1
  1005. wagtail/snippets/locale/uk/LC_MESSAGES/django.po +1 -1
  1006. wagtail/snippets/locale/vi/LC_MESSAGES/django.po +1 -1
  1007. wagtail/snippets/locale/zh/LC_MESSAGES/django.po +1 -1
  1008. wagtail/snippets/locale/zh_Hans/LC_MESSAGES/django.po +1 -1
  1009. wagtail/snippets/locale/zh_Hant/LC_MESSAGES/django.po +1 -1
  1010. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser-telepath.js +1 -1
  1011. wagtail/snippets/static/wagtailsnippets/js/snippet-chooser.js +1 -1
  1012. wagtail/snippets/tests/test_reordering.py +319 -0
  1013. wagtail/snippets/tests/test_snippets.py +77 -12
  1014. wagtail/snippets/views/snippets.py +16 -0
  1015. wagtail/test/numberformat.py +30 -0
  1016. wagtail/test/settings.py +35 -12
  1017. wagtail/test/testapp/fields.py +12 -0
  1018. wagtail/test/testapp/migrations/0056_commentablejsonpage.py +50 -0
  1019. wagtail/test/testapp/migrations/0057_featurecompletetoy_sort_order.py +23 -0
  1020. wagtail/test/testapp/migrations/0058_customlocktask.py +31 -0
  1021. wagtail/test/testapp/models.py +27 -0
  1022. wagtail/test/testapp/views.py +3 -1
  1023. wagtail/test/utils/page_tests.py +17 -17
  1024. wagtail/test/utils/template_tests.py +4 -6
  1025. wagtail/test/utils/wagtail_tests.py +1 -2
  1026. wagtail/tests/test_page_model.py +15 -0
  1027. wagtail/{search/tests → tests}/test_page_search.py +29 -2
  1028. wagtail/tests/test_search_fields.py +69 -0
  1029. wagtail/tests/test_tests.py +62 -6
  1030. wagtail/tests/test_workflow.py +25 -1
  1031. wagtail/users/locale/ar/LC_MESSAGES/django.po +1 -1
  1032. wagtail/users/locale/be/LC_MESSAGES/django.po +1 -1
  1033. wagtail/users/locale/bg/LC_MESSAGES/django.po +1 -1
  1034. wagtail/users/locale/bn/LC_MESSAGES/django.po +1 -1
  1035. wagtail/users/locale/ca/LC_MESSAGES/django.po +1 -1
  1036. wagtail/users/locale/cs/LC_MESSAGES/django.mo +0 -0
  1037. wagtail/users/locale/cs/LC_MESSAGES/django.po +4 -1
  1038. wagtail/users/locale/cy/LC_MESSAGES/django.po +1 -1
  1039. wagtail/users/locale/da/LC_MESSAGES/django.po +1 -1
  1040. wagtail/users/locale/de/LC_MESSAGES/django.po +1 -1
  1041. wagtail/users/locale/dv/LC_MESSAGES/django.po +1 -1
  1042. wagtail/users/locale/el/LC_MESSAGES/django.po +1 -1
  1043. wagtail/users/locale/en/LC_MESSAGES/django.po +2 -2
  1044. wagtail/users/locale/es/LC_MESSAGES/django.po +1 -1
  1045. wagtail/users/locale/es_419/LC_MESSAGES/django.po +1 -1
  1046. wagtail/users/locale/et/LC_MESSAGES/django.po +1 -1
  1047. wagtail/users/locale/eu/LC_MESSAGES/django.po +1 -1
  1048. wagtail/users/locale/fa/LC_MESSAGES/django.po +1 -1
  1049. wagtail/users/locale/fi/LC_MESSAGES/django.mo +0 -0
  1050. wagtail/users/locale/fi/LC_MESSAGES/django.po +6 -3
  1051. wagtail/users/locale/fr/LC_MESSAGES/django.po +1 -1
  1052. wagtail/users/locale/gl/LC_MESSAGES/django.po +1 -1
  1053. wagtail/users/locale/he_IL/LC_MESSAGES/django.po +1 -1
  1054. wagtail/users/locale/hr_HR/LC_MESSAGES/django.po +1 -1
  1055. wagtail/users/locale/hu/LC_MESSAGES/django.po +1 -1
  1056. wagtail/users/locale/hy/LC_MESSAGES/django.po +1 -1
  1057. wagtail/users/locale/id_ID/LC_MESSAGES/django.po +1 -1
  1058. wagtail/users/locale/is_IS/LC_MESSAGES/django.po +1 -1
  1059. wagtail/users/locale/it/LC_MESSAGES/django.po +1 -1
  1060. wagtail/users/locale/ja/LC_MESSAGES/django.po +1 -1
  1061. wagtail/users/locale/ka/LC_MESSAGES/django.po +1 -1
  1062. wagtail/users/locale/ko/LC_MESSAGES/django.po +1 -1
  1063. wagtail/users/locale/lt/LC_MESSAGES/django.po +1 -1
  1064. wagtail/users/locale/lv/LC_MESSAGES/django.po +1 -1
  1065. wagtail/users/locale/mi/LC_MESSAGES/django.po +1 -1
  1066. wagtail/users/locale/mn/LC_MESSAGES/django.po +1 -1
  1067. wagtail/users/locale/my/LC_MESSAGES/django.po +1 -1
  1068. wagtail/users/locale/nb/LC_MESSAGES/django.po +1 -1
  1069. wagtail/users/locale/nl/LC_MESSAGES/django.mo +0 -0
  1070. wagtail/users/locale/nl/LC_MESSAGES/django.po +7 -4
  1071. wagtail/users/locale/pl/LC_MESSAGES/django.po +1 -1
  1072. wagtail/users/locale/pt_BR/LC_MESSAGES/django.po +1 -1
  1073. wagtail/users/locale/pt_PT/LC_MESSAGES/django.po +1 -1
  1074. wagtail/users/locale/ro/LC_MESSAGES/django.po +1 -1
  1075. wagtail/users/locale/ru/LC_MESSAGES/django.mo +0 -0
  1076. wagtail/users/locale/ru/LC_MESSAGES/django.po +6 -2
  1077. wagtail/users/locale/sk_SK/LC_MESSAGES/django.po +1 -1
  1078. wagtail/users/locale/sl/LC_MESSAGES/django.po +1 -1
  1079. wagtail/users/locale/sv/LC_MESSAGES/django.po +1 -1
  1080. wagtail/users/locale/tet/LC_MESSAGES/django.po +1 -1
  1081. wagtail/users/locale/th/LC_MESSAGES/django.po +1 -1
  1082. wagtail/users/locale/tr/LC_MESSAGES/django.mo +0 -0
  1083. wagtail/users/locale/tr/LC_MESSAGES/django.po +79 -5
  1084. wagtail/users/locale/tr_TR/LC_MESSAGES/django.po +1 -1
  1085. wagtail/users/locale/ug/LC_MESSAGES/django.po +1 -1
  1086. wagtail/users/locale/uk/LC_MESSAGES/django.po +1 -1
  1087. wagtail/users/locale/vi/LC_MESSAGES/django.po +1 -1
  1088. wagtail/users/locale/zh/LC_MESSAGES/django.po +1 -1
  1089. wagtail/users/locale/zh_Hans/LC_MESSAGES/django.po +1 -1
  1090. wagtail/users/locale/zh_Hant/LC_MESSAGES/django.po +1 -1
  1091. wagtail/users/templates/wagtailusers/users/create.html +2 -0
  1092. wagtail/users/templates/wagtailusers/users/edit.html +2 -0
  1093. wagtail/users/tests/test_admin_views.py +4 -0
  1094. wagtail/users/views/users.py +1 -1
  1095. {wagtail-7.1.2.dist-info → wagtail-7.2.dist-info}/METADATA +8 -7
  1096. {wagtail-7.1.2.dist-info → wagtail-7.2.dist-info}/RECORD +1102 -1108
  1097. wagtail/admin/templates/wagtailadmin/collection_privacy/set_privacy.html +0 -13
  1098. wagtail/admin/templates/wagtailadmin/page_privacy/set_privacy.html +0 -13
  1099. wagtail/search/tests/__init__.py +0 -0
  1100. wagtail/search/tests/elasticsearch_common_tests.py +0 -251
  1101. wagtail/search/tests/test_backends.py +0 -1215
  1102. wagtail/search/tests/test_db_backend.py +0 -62
  1103. wagtail/search/tests/test_elasticsearch7_backend.py +0 -1452
  1104. wagtail/search/tests/test_elasticsearch8_backend.py +0 -15
  1105. wagtail/search/tests/test_index_functions.py +0 -256
  1106. wagtail/search/tests/test_indexed_class.py +0 -157
  1107. wagtail/search/tests/test_mysql_backend.py +0 -192
  1108. wagtail/search/tests/test_postgres_backend.py +0 -210
  1109. wagtail/search/tests/test_queries.py +0 -332
  1110. wagtail/search/tests/test_related_fields.py +0 -102
  1111. wagtail/search/tests/test_sqlite_backend.py +0 -52
  1112. wagtail/test/search/__init__.py +0 -0
  1113. wagtail/test/search/apps.py +0 -9
  1114. wagtail/test/search/fixtures/search.json +0 -545
  1115. wagtail/test/search/migrations/0001_initial.py +0 -146
  1116. wagtail/test/search/migrations/0002_bookunindexed.py +0 -43
  1117. wagtail/test/search/migrations/0003_book_summary.py +0 -18
  1118. wagtail/test/search/migrations/__init__.py +0 -0
  1119. wagtail/test/search/models.py +0 -137
  1120. /wagtail/admin/templates/wagtailadmin/{pages/listing/_ordering_cell.html → tables/ordering_cell.html} +0 -0
  1121. /wagtail/{search/checks.py → checks.py} +0 -0
  1122. {wagtail-7.1.2.dist-info → wagtail-7.2.dist-info}/WHEEL +0 -0
  1123. {wagtail-7.1.2.dist-info → wagtail-7.2.dist-info}/entry_points.txt +0 -0
  1124. {wagtail-7.1.2.dist-info → wagtail-7.2.dist-info}/licenses/LICENSE +0 -0
  1125. {wagtail-7.1.2.dist-info → wagtail-7.2.dist-info}/top_level.txt +0 -0
@@ -1,1277 +1,35 @@
1
- import json
2
- from collections import OrderedDict
3
- from copy import deepcopy
4
- from urllib.parse import urlparse
5
-
6
- from django.db import DEFAULT_DB_ALIAS, models
7
- from django.db.models import Subquery
8
- from django.db.models.sql import Query
9
- from django.db.models.sql.constants import MULTI, SINGLE
10
- from django.utils.crypto import get_random_string
11
- from elasticsearch import VERSION as ELASTICSEARCH_VERSION
12
- from elasticsearch import Elasticsearch, NotFoundError
13
- from elasticsearch.helpers import bulk
14
-
15
- from wagtail.search.backends.base import (
16
- BaseSearchBackend,
17
- BaseSearchQueryCompiler,
18
- BaseSearchResults,
19
- FilterFieldError,
20
- get_model_root,
1
+ from modelsearch.backends.elasticsearch7 import * # noqa: F403
2
+ from modelsearch.backends.elasticsearch7 import (
3
+ Elasticsearch7AutocompleteQueryCompiler as _Elasticsearch7AutocompleteQueryCompiler,
21
4
  )
22
- from wagtail.search.index import (
23
- AutocompleteField,
24
- FilterField,
25
- Indexed,
26
- RelatedFields,
27
- SearchField,
28
- class_is_indexed,
29
- get_indexed_models,
5
+ from modelsearch.backends.elasticsearch7 import (
6
+ Elasticsearch7SearchBackend as _Elasticsearch7SearchBackend,
7
+ )
8
+ from modelsearch.backends.elasticsearch7 import (
9
+ Elasticsearch7SearchQueryCompiler as _Elasticsearch7SearchQueryCompiler,
30
10
  )
31
- from wagtail.search.query import And, Boost, Fuzzy, MatchAll, Not, Or, Phrase, PlainText
32
- from wagtail.utils.utils import deep_update
33
-
34
- use_new_elasticsearch_api = ELASTICSEARCH_VERSION >= (7, 15)
35
-
36
-
37
- class Field:
38
- def __init__(self, field_name, boost=1):
39
- self.field_name = field_name
40
- self.boost = boost
41
-
42
- @property
43
- def field_name_with_boost(self):
44
- if self.boost == 1:
45
- return self.field_name
46
- else:
47
- return f"{self.field_name}^{self.boost}"
48
-
49
-
50
- class Elasticsearch7Mapping:
51
- all_field_name = "_all_text"
52
- edgengrams_field_name = "_edgengrams"
53
-
54
- type_map = {
55
- "AutoField": "integer",
56
- "SmallAutoField": "integer",
57
- "BigAutoField": "long",
58
- "BinaryField": "binary",
59
- "BooleanField": "boolean",
60
- "CharField": "string",
61
- "CommaSeparatedIntegerField": "string",
62
- "DateField": "date",
63
- "DateTimeField": "date",
64
- "DecimalField": "double",
65
- "FileField": "string",
66
- "FilePathField": "string",
67
- "FloatField": "double",
68
- "IntegerField": "integer",
69
- "BigIntegerField": "long",
70
- "IPAddressField": "string",
71
- "GenericIPAddressField": "string",
72
- "NullBooleanField": "boolean",
73
- "PositiveIntegerField": "integer",
74
- "PositiveSmallIntegerField": "integer",
75
- "PositiveBigIntegerField": "long",
76
- "SlugField": "string",
77
- "SmallIntegerField": "integer",
78
- "TextField": "string",
79
- "TimeField": "date",
80
- "URLField": "string",
81
- }
82
-
83
- keyword_type = "keyword"
84
- text_type = "text"
85
- edgengram_analyzer_config = {
86
- "analyzer": "edgengram_analyzer",
87
- "search_analyzer": "standard",
88
- }
89
-
90
- def __init__(self, model):
91
- self.model = model
92
-
93
- def get_parent(self):
94
- for base in self.model.__bases__:
95
- if issubclass(base, Indexed) and issubclass(base, models.Model):
96
- return type(self)(base)
97
-
98
- def get_document_type(self):
99
- return "doc"
100
-
101
- def get_field_column_name(self, field):
102
- # Fields in derived models get prefixed with their model name, fields
103
- # in the root model don't get prefixed at all
104
- # This is to prevent mapping clashes in cases where two page types have
105
- # a field with the same name but a different type.
106
- root_model = get_model_root(self.model)
107
- definition_model = field.get_definition_model(self.model)
108
-
109
- if definition_model != root_model:
110
- prefix = (
111
- definition_model._meta.app_label.lower()
112
- + "_"
113
- + definition_model.__name__.lower()
114
- + "__"
115
- )
116
- else:
117
- prefix = ""
118
-
119
- if isinstance(field, FilterField):
120
- return prefix + field.get_attname(self.model) + "_filter"
121
- elif isinstance(field, AutocompleteField):
122
- return prefix + field.get_attname(self.model) + "_edgengrams"
123
- elif isinstance(field, SearchField):
124
- return prefix + field.get_attname(self.model)
125
- elif isinstance(field, RelatedFields):
126
- return prefix + field.field_name
127
-
128
- def get_boost_field_name(self, boost):
129
- # replace . with _ to avoid issues with . in field names
130
- boost = str(float(boost)).replace(".", "_")
131
- return f"{self.all_field_name}_boost_{boost}"
132
-
133
- def get_content_type(self):
134
- """
135
- Returns the content type as a string for the model.
136
-
137
- For example: "wagtailcore.Page"
138
- "myapp.MyModel"
139
- """
140
- return self.model._meta.app_label + "." + self.model.__name__
141
-
142
- def get_all_content_types(self):
143
- """
144
- Returns all the content type strings that apply to this model.
145
- This includes the models' content type and all concrete ancestor
146
- models that inherit from Indexed.
147
-
148
- For example: ["myapp.MyPageModel", "wagtailcore.Page"]
149
- ["myapp.MyModel"]
150
- """
151
- # Add our content type
152
- content_types = [self.get_content_type()]
153
-
154
- # Add all ancestor classes content types as well
155
- ancestor = self.get_parent()
156
- while ancestor:
157
- content_types.append(ancestor.get_content_type())
158
- ancestor = ancestor.get_parent()
159
-
160
- return content_types
161
-
162
- def get_field_mapping(self, field):
163
- if isinstance(field, RelatedFields):
164
- mapping = {"type": "nested", "properties": {}}
165
- nested_model = field.get_field(self.model).related_model
166
- nested_mapping = type(self)(nested_model)
167
-
168
- for sub_field in field.fields:
169
- sub_field_name, sub_field_mapping = nested_mapping.get_field_mapping(
170
- sub_field
171
- )
172
- mapping["properties"][sub_field_name] = sub_field_mapping
173
-
174
- return self.get_field_column_name(field), mapping
175
- else:
176
- mapping = {"type": self.type_map.get(field.get_type(self.model), "string")}
177
-
178
- if isinstance(field, SearchField):
179
- if mapping["type"] == "string":
180
- mapping["type"] = self.text_type
181
-
182
- if field.boost:
183
- mapping["boost"] = field.boost
184
-
185
- mapping["include_in_all"] = True
186
-
187
- if isinstance(field, AutocompleteField):
188
- mapping["type"] = self.text_type
189
- mapping.update(self.edgengram_analyzer_config)
190
-
191
- elif isinstance(field, FilterField):
192
- if mapping["type"] == "string":
193
- mapping["type"] = self.keyword_type
194
-
195
- if "es_extra" in field.kwargs:
196
- for key, value in field.kwargs["es_extra"].items():
197
- mapping[key] = value
198
-
199
- return self.get_field_column_name(field), mapping
200
-
201
- def get_mapping(self):
202
- # Make field list
203
- fields = {
204
- "pk": {"type": self.keyword_type, "store": True},
205
- "content_type": {"type": self.keyword_type},
206
- self.edgengrams_field_name: {"type": self.text_type},
207
- }
208
- fields[self.edgengrams_field_name].update(self.edgengram_analyzer_config)
209
-
210
- for field in self.model.get_search_fields():
211
- key, val = self.get_field_mapping(field)
212
- fields[key] = val
213
-
214
- # Add _all_text field
215
- fields[self.all_field_name] = {"type": "text"}
216
-
217
- unique_boosts = set()
218
-
219
- # Replace {"include_in_all": true} with {"copy_to": ["_all_text", "_all_text_boost_2"]}
220
- def replace_include_in_all(properties):
221
- for field_mapping in properties.values():
222
- if "include_in_all" in field_mapping:
223
- if field_mapping["include_in_all"]:
224
- field_mapping["copy_to"] = self.all_field_name
225
-
226
- if "boost" in field_mapping:
227
- # added to unique_boosts to avoid duplicate fields, or cases like 2.0 and 2
228
- unique_boosts.add(field_mapping["boost"])
229
- field_mapping["copy_to"] = [
230
- field_mapping["copy_to"],
231
- self.get_boost_field_name(field_mapping["boost"]),
232
- ]
233
- del field_mapping["boost"]
234
-
235
- del field_mapping["include_in_all"]
236
-
237
- if field_mapping["type"] == "nested":
238
- replace_include_in_all(field_mapping["properties"])
239
-
240
- replace_include_in_all(fields)
241
- for boost in unique_boosts:
242
- fields[self.get_boost_field_name(boost)] = {"type": "text"}
243
-
244
- return {
245
- "properties": fields,
246
- }
247
-
248
- def get_document_id(self, obj):
249
- return str(obj.pk)
250
-
251
- def _get_nested_document(self, fields, obj):
252
- doc = {}
253
- edgengrams = []
254
- model = type(obj)
255
- mapping = type(self)(model)
256
-
257
- for field in fields:
258
- value = field.get_value(obj)
259
- doc[mapping.get_field_column_name(field)] = value
260
-
261
- # Check if this field should be added into _edgengrams
262
- if isinstance(field, AutocompleteField):
263
- edgengrams.append(value)
264
-
265
- return doc, edgengrams
266
-
267
- def get_document(self, obj):
268
- # Build document
269
- doc = {"pk": str(obj.pk), "content_type": self.get_all_content_types()}
270
- edgengrams = []
271
- for field in self.model.get_search_fields():
272
- value = field.get_value(obj)
273
-
274
- if isinstance(field, RelatedFields):
275
- if isinstance(value, (models.Manager, models.QuerySet)):
276
- nested_docs = []
277
-
278
- for nested_obj in value.all():
279
- nested_doc, extra_edgengrams = self._get_nested_document(
280
- field.fields, nested_obj
281
- )
282
- nested_docs.append(nested_doc)
283
- edgengrams.extend(extra_edgengrams)
284
-
285
- value = nested_docs
286
- elif isinstance(value, models.Model):
287
- value, extra_edgengrams = self._get_nested_document(
288
- field.fields, value
289
- )
290
- edgengrams.extend(extra_edgengrams)
291
- elif isinstance(field, FilterField):
292
- if isinstance(value, (models.Manager, models.QuerySet)):
293
- value = list(value.values_list("pk", flat=True))
294
- elif isinstance(value, models.Model):
295
- value = value.pk
296
- elif isinstance(value, (list, tuple)):
297
- value = [
298
- item.pk if isinstance(item, models.Model) else item
299
- for item in value
300
- ]
301
-
302
- doc[self.get_field_column_name(field)] = value
303
-
304
- # Check if this field should be added into _edgengrams
305
- if isinstance(field, AutocompleteField):
306
- edgengrams.append(value)
307
-
308
- # Add partials to document
309
- doc[self.edgengrams_field_name] = edgengrams
310
-
311
- return doc
312
-
313
- def __repr__(self):
314
- return f"<ElasticsearchMapping: {self.model.__name__}>"
315
-
316
-
317
- class Elasticsearch7Index:
318
- def __init__(self, backend, name):
319
- self.backend = backend
320
- self.es = backend.es
321
- self.mapping_class = backend.mapping_class
322
- self.name = name
323
-
324
- if use_new_elasticsearch_api:
325
-
326
- def put(self):
327
- self.es.indices.create(index=self.name, **self.backend.settings)
328
-
329
- def delete(self):
330
- try:
331
- self.es.indices.delete(index=self.name)
332
- except NotFoundError:
333
- pass
334
-
335
- def refresh(self):
336
- self.es.indices.refresh(index=self.name)
337
-
338
- else:
339
-
340
- def put(self):
341
- self.es.indices.create(self.name, self.backend.settings)
342
-
343
- def delete(self):
344
- try:
345
- self.es.indices.delete(self.name)
346
- except NotFoundError:
347
- pass
348
-
349
- def refresh(self):
350
- self.es.indices.refresh(self.name)
351
-
352
- def exists(self):
353
- return self.es.indices.exists(self.name)
354
-
355
- def is_alias(self):
356
- return self.es.indices.exists_alias(name=self.name)
357
-
358
- def aliased_indices(self):
359
- """
360
- If this index object represents an alias (which appear the same in the
361
- Elasticsearch API), this method can be used to fetch the list of indices
362
- the alias points to.
363
-
364
- Use the is_alias method if you need to find out if this an alias. This
365
- returns an empty list if called on an index.
366
- """
367
- return [
368
- self.backend.index_class(self.backend, index_name)
369
- for index_name in self.es.indices.get_alias(name=self.name).keys()
370
- ]
371
-
372
- def put_alias(self, name):
373
- """
374
- Creates a new alias to this index. If the alias already exists it will
375
- be repointed to this index.
376
- """
377
- self.es.indices.put_alias(name=name, index=self.name)
378
-
379
- def add_model(self, model):
380
- # Get mapping
381
- mapping = self.mapping_class(model)
382
-
383
- # Put mapping
384
- self.es.indices.put_mapping(index=self.name, body=mapping.get_mapping())
385
-
386
- if use_new_elasticsearch_api:
387
-
388
- def add_item(self, item):
389
- # Make sure the object can be indexed
390
- if not class_is_indexed(item.__class__):
391
- return
392
-
393
- # Get mapping
394
- mapping = self.mapping_class(item.__class__)
395
-
396
- # Add document to index
397
- self.es.index(
398
- index=self.name,
399
- document=mapping.get_document(item),
400
- id=mapping.get_document_id(item),
401
- )
402
-
403
- else:
404
-
405
- def add_item(self, item):
406
- # Make sure the object can be indexed
407
- if not class_is_indexed(item.__class__):
408
- return
409
- # Get mapping
410
- mapping = self.mapping_class(item.__class__)
411
-
412
- # Add document to index
413
- self.es.index(
414
- self.name, mapping.get_document(item), id=mapping.get_document_id(item)
415
- )
416
-
417
- def add_items(self, model, items):
418
- if not class_is_indexed(model):
419
- return
420
-
421
- # Get mapping
422
- mapping = self.mapping_class(model)
423
-
424
- # Create list of actions
425
- actions = []
426
- for item in items:
427
- # Create the action
428
- action = {"_id": mapping.get_document_id(item)}
429
- action.update(mapping.get_document(item))
430
- actions.append(action)
431
-
432
- # Run the actions
433
- bulk(self.es, actions, index=self.name)
434
-
435
- def delete_item(self, item):
436
- # Make sure the object can be indexed
437
- if not class_is_indexed(item.__class__):
438
- return
439
-
440
- # Get mapping
441
- mapping = self.mapping_class(item.__class__)
442
-
443
- # Delete document
444
- try:
445
- self.es.delete(index=self.name, id=mapping.get_document_id(item))
446
- except NotFoundError:
447
- pass # Document doesn't exist, ignore this exception
448
-
449
- def reset(self):
450
- # Delete old index
451
- self.delete()
452
-
453
- # Create new index
454
- self.put()
455
-
456
-
457
- class Elasticsearch7SearchQueryCompiler(BaseSearchQueryCompiler):
458
- mapping_class = Elasticsearch7Mapping
459
- DEFAULT_OPERATOR = "or"
460
-
461
- def __init__(self, *args, **kwargs):
462
- super().__init__(*args, **kwargs)
463
- self.mapping = self.mapping_class(self.queryset.model)
464
- self.remapped_fields = self._remap_fields(self.fields)
465
-
466
- def _remap_fields(self, fields):
467
- """Convert field names into index column names and add boosts."""
468
-
469
- remapped_fields = []
470
- if fields:
471
- searchable_fields = {f.field_name: f for f in self.get_searchable_fields()}
472
- for field_name in fields:
473
- field = searchable_fields.get(field_name)
474
- if field:
475
- field_name = self.mapping.get_field_column_name(field)
476
- remapped_fields.append(Field(field_name, field.boost or 1))
477
- else:
478
- remapped_fields.append(Field(self.mapping.all_field_name))
479
-
480
- models = get_indexed_models()
481
- unique_boosts = set()
482
- for model in models:
483
- if not issubclass(model, self.queryset.model):
484
- continue
485
- for field in model.get_searchable_search_fields():
486
- if field.boost:
487
- unique_boosts.add(float(field.boost))
488
-
489
- remapped_fields.extend(
490
- [
491
- Field(self.mapping.get_boost_field_name(boost), boost)
492
- for boost in unique_boosts
493
- ]
494
- )
495
-
496
- return remapped_fields
497
-
498
- def _process_lookup(self, field, lookup, value):
499
- column_name = self.mapping.get_field_column_name(field)
500
-
501
- if lookup == "exact":
502
- if value is None:
503
- return {
504
- "missing": {
505
- "field": column_name,
506
- }
507
- }
508
- else:
509
- if isinstance(value, (Query, Subquery)):
510
- db_alias = self.queryset._db or DEFAULT_DB_ALIAS
511
- query = value.query if isinstance(value, Subquery) else value
512
- value = query.get_compiler(db_alias).execute_sql(result_type=SINGLE)
513
- # The result is either a tuple with one element or None
514
- if value:
515
- value = value[0]
516
-
517
- return {
518
- "term": {
519
- column_name: value,
520
- }
521
- }
522
-
523
- if lookup == "isnull":
524
- query = {
525
- "exists": {
526
- "field": column_name,
527
- }
528
- }
529
-
530
- if value:
531
- query = {"bool": {"mustNot": query}}
532
-
533
- return query
534
-
535
- if lookup in ["startswith", "prefix"]:
536
- return {
537
- "prefix": {
538
- column_name: value,
539
- }
540
- }
541
-
542
- if lookup in ["gt", "gte", "lt", "lte"]:
543
- return {
544
- "range": {
545
- column_name: {
546
- lookup: value,
547
- }
548
- }
549
- }
550
-
551
- if lookup == "range":
552
- lower, upper = value
553
-
554
- return {
555
- "range": {
556
- column_name: {
557
- "gte": lower,
558
- "lte": upper,
559
- }
560
- }
561
- }
562
-
563
- if lookup == "in":
564
- if isinstance(value, (Query, Subquery)):
565
- db_alias = self.queryset._db or DEFAULT_DB_ALIAS
566
- query = value.query if isinstance(value, Subquery) else value
567
- resultset = query.get_compiler(db_alias).execute_sql(result_type=MULTI)
568
- value = [row[0] for chunk in resultset for row in chunk]
569
-
570
- elif not isinstance(value, list):
571
- value = list(value)
572
- return {
573
- "terms": {
574
- column_name: value,
575
- }
576
- }
577
-
578
- def _process_match_none(self):
579
- return {"bool": {"mustNot": {"match_all": {}}}}
580
-
581
- def _connect_filters(self, filters, connector, negated):
582
- if filters:
583
- if len(filters) == 1:
584
- filter_out = filters[0]
585
- elif connector == "AND":
586
- filter_out = {
587
- "bool": {"must": [fil for fil in filters if fil is not None]}
588
- }
589
- elif connector == "OR":
590
- filter_out = {
591
- "bool": {"should": [fil for fil in filters if fil is not None]}
592
- }
593
-
594
- if negated:
595
- filter_out = {"bool": {"mustNot": filter_out}}
596
-
597
- return filter_out
598
-
599
- def _compile_plaintext_query(self, query, fields, boost=1.0):
600
- match_query = {"query": query.query_string}
601
-
602
- if query.operator != "or":
603
- match_query["operator"] = query.operator
604
-
605
- if len(fields) == 1:
606
- if boost != 1.0 or fields[0].boost != 1.0:
607
- match_query["boost"] = boost * fields[0].boost
608
- return {"match": {fields[0].field_name: match_query}}
609
- else:
610
- if boost != 1.0:
611
- match_query["boost"] = boost
612
- match_query["fields"] = [field.field_name_with_boost for field in fields]
613
-
614
- return {"multi_match": match_query}
615
-
616
- def _compile_fuzzy_query(self, query, fields):
617
- match_query = {
618
- "query": query.query_string,
619
- "fuzziness": "AUTO",
620
- }
621
-
622
- if query.operator != "or":
623
- match_query["operator"] = query.operator
624
-
625
- if len(fields) == 1:
626
- if fields[0].boost != 1.0:
627
- match_query["boost"] = fields[0].boost
628
- return {"match": {fields[0].field_name: match_query}}
629
- else:
630
- match_query["fields"] = [field.field_name_with_boost for field in fields]
631
- return {"multi_match": match_query}
632
-
633
- def _compile_phrase_query(self, query, fields):
634
- if len(fields) == 1:
635
- if fields[0].boost != 1.0:
636
- return {
637
- "match_phrase": {
638
- fields[0].field_name: {
639
- "query": query.query_string,
640
- "boost": fields[0].boost,
641
- }
642
- }
643
- }
644
- else:
645
- return {"match_phrase": {fields[0].field_name: query.query_string}}
646
- else:
647
- return {
648
- "multi_match": {
649
- "query": query.query_string,
650
- "fields": [field.field_name_with_boost for field in fields],
651
- "type": "phrase",
652
- }
653
- }
654
-
655
- def _compile_query(self, query, field, boost=1.0):
656
- if isinstance(query, MatchAll):
657
- match_all_query = {}
658
-
659
- if boost != 1.0:
660
- match_all_query["boost"] = boost
661
-
662
- return {"match_all": match_all_query}
663
-
664
- elif isinstance(query, And):
665
- return {
666
- "bool": {
667
- "must": [
668
- self._compile_query(child_query, field, boost)
669
- for child_query in query.subqueries
670
- ]
671
- }
672
- }
673
-
674
- elif isinstance(query, Or):
675
- return {
676
- "bool": {
677
- "should": [
678
- self._compile_query(child_query, field, boost)
679
- for child_query in query.subqueries
680
- ]
681
- }
682
- }
683
-
684
- elif isinstance(query, Not):
685
- return {
686
- "bool": {"mustNot": self._compile_query(query.subquery, field, boost)}
687
- }
688
-
689
- elif isinstance(query, PlainText):
690
- return self._compile_plaintext_query(query, [field], boost)
691
-
692
- elif isinstance(query, Fuzzy):
693
- return self._compile_fuzzy_query(query, [field])
694
-
695
- elif isinstance(query, Phrase):
696
- return self._compile_phrase_query(query, [field])
697
-
698
- elif isinstance(query, Boost):
699
- return self._compile_query(query.subquery, field, boost * query.boost)
700
-
701
- else:
702
- raise NotImplementedError(
703
- "`%s` is not supported by the Elasticsearch search backend."
704
- % query.__class__.__name__
705
- )
706
-
707
- def get_inner_query(self):
708
- if self.remapped_fields:
709
- fields = self.remapped_fields
710
- else:
711
- fields = [self.mapping.all_field_name]
712
-
713
- if len(fields) == 0:
714
- # No fields. Return a query that'll match nothing
715
- return {"bool": {"mustNot": {"match_all": {}}}}
716
-
717
- # Handle MatchAll and PlainText separately as they were supported
718
- # before "search query classes" was implemented and we'd like to
719
- # keep the query the same as before
720
- if isinstance(self.query, MatchAll):
721
- return {"match_all": {}}
722
-
723
- elif isinstance(self.query, PlainText):
724
- return self._compile_plaintext_query(self.query, fields)
725
-
726
- elif isinstance(self.query, Phrase):
727
- return self._compile_phrase_query(self.query, fields)
728
-
729
- elif isinstance(self.query, Fuzzy):
730
- return self._compile_fuzzy_query(self.query, fields)
731
-
732
- elif isinstance(self.query, Not):
733
- return {
734
- "bool": {
735
- "mustNot": [
736
- self._compile_query(self.query.subquery, field)
737
- for field in fields
738
- ]
739
- }
740
- }
741
-
742
- else:
743
- return self._join_and_compile_queries(self.query, fields)
744
-
745
- def _join_and_compile_queries(self, query, fields, boost=1.0):
746
- if len(fields) == 1:
747
- return self._compile_query(query, fields[0], boost)
748
- else:
749
- # Compile a query for each field then combine with disjunction
750
- # max (or operator which takes the max score out of each of the
751
- # field queries)
752
- field_queries = []
753
- for field in fields:
754
- field_queries.append(self._compile_query(query, field, boost))
755
-
756
- return {"dis_max": {"queries": field_queries}}
757
-
758
- def get_content_type_filter(self):
759
- # Query content_type using a "match" query. See comment in
760
- # Elasticsearch7Mapping.get_document for more details
761
- content_type = self.mapping_class(self.queryset.model).get_content_type()
762
-
763
- return {"match": {"content_type": content_type}}
764
-
765
- def get_filters(self):
766
- # Filter by content type
767
- filters = [self.get_content_type_filter()]
768
-
769
- # Apply filters from queryset
770
- queryset_filters = self._get_filters_from_queryset()
771
- if queryset_filters:
772
- filters.append(queryset_filters)
773
-
774
- return filters
775
-
776
- def get_query(self):
777
- inner_query = self.get_inner_query()
778
- filters = self.get_filters()
779
-
780
- if len(filters) == 1:
781
- return {
782
- "bool": {
783
- "must": inner_query,
784
- "filter": filters[0],
785
- }
786
- }
787
- elif len(filters) > 1:
788
- return {
789
- "bool": {
790
- "must": inner_query,
791
- "filter": filters,
792
- }
793
- }
794
- else:
795
- return inner_query
796
-
797
- def get_searchable_fields(self):
798
- return self.queryset.model.get_searchable_search_fields()
799
-
800
- def get_sort(self):
801
- # Ordering by relevance is the default in Elasticsearch
802
- if self.order_by_relevance:
803
- return
804
-
805
- # Get queryset and make sure its ordered
806
- if self.queryset.ordered:
807
- sort = []
808
-
809
- for reverse, field in self._get_order_by():
810
- column_name = self.mapping.get_field_column_name(field)
811
-
812
- sort.append({column_name: "desc" if reverse else "asc"})
813
-
814
- return sort
815
-
816
- else:
817
- # Order by pk field
818
- return ["pk"]
819
-
820
- def __repr__(self):
821
- return json.dumps(self.get_query())
822
-
823
-
824
- class Elasticsearch7SearchResults(BaseSearchResults):
825
- fields_param_name = "stored_fields"
826
- supports_facet = True
827
-
828
- def facet(self, field_name):
829
- # Get field
830
- field = self.query_compiler._get_filterable_field(field_name)
831
- if field is None:
832
- raise FilterFieldError(
833
- 'Cannot facet search results with field "'
834
- + field_name
835
- + "\". Please add index.FilterField('"
836
- + field_name
837
- + "') to "
838
- + self.query_compiler.queryset.model.__name__
839
- + ".search_fields.",
840
- field_name=field_name,
841
- )
842
-
843
- # Build body
844
- body = self._get_es_body()
845
- column_name = self.query_compiler.mapping.get_field_column_name(field)
846
-
847
- body["aggregations"] = {
848
- field_name: {
849
- "terms": {
850
- "field": column_name,
851
- "missing": 0,
852
- }
853
- }
854
- }
855
-
856
- # Send to Elasticsearch
857
- response = self._backend_do_search(
858
- body,
859
- index=self.backend.get_index_for_model(
860
- self.query_compiler.queryset.model
861
- ).name,
862
- size=0,
863
- )
864
-
865
- return OrderedDict(
866
- [
867
- (bucket["key"] if bucket["key"] != 0 else None, bucket["doc_count"])
868
- for bucket in response["aggregations"][field_name]["buckets"]
869
- ]
870
- )
871
-
872
- def _get_es_body(self, for_count=False):
873
- body = {"query": self.query_compiler.get_query()}
874
-
875
- if not for_count:
876
- sort = self.query_compiler.get_sort()
877
-
878
- if sort is not None:
879
- body["sort"] = sort
880
-
881
- return body
882
-
883
- def _get_results_from_hits(self, hits):
884
- """
885
- Yields Django model instances from a page of hits returned by Elasticsearch
886
- """
887
- # Get pks from results
888
- pks = [hit["fields"]["pk"][0] for hit in hits]
889
- scores = {str(hit["fields"]["pk"][0]): hit["_score"] for hit in hits}
890
-
891
- # Initialise results dictionary
892
- results = {str(pk): None for pk in pks}
893
-
894
- # Find objects in database and add them to dict
895
- for obj in self.query_compiler.queryset.filter(pk__in=pks):
896
- results[str(obj.pk)] = obj
897
-
898
- if self._score_field:
899
- setattr(obj, self._score_field, scores.get(str(obj.pk)))
900
-
901
- # Yield results in order given by Elasticsearch
902
- for pk in pks:
903
- result = results[str(pk)]
904
- if result:
905
- yield result
906
-
907
- if use_new_elasticsearch_api:
908
-
909
- def _backend_do_search(self, body, **kwargs):
910
- # As of Elasticsearch 7.15, the 'body' parameter is deprecated; instead, the top-level
911
- # keys of the body dict are now kwargs in their own right
912
- return self.backend.es.search(**body, **kwargs)
913
-
914
- else:
915
-
916
- def _backend_do_search(self, body, **kwargs):
917
- # Send the search query to the backend.
918
- return self.backend.es.search(body=body, **kwargs)
919
-
920
- def _do_search(self):
921
- PAGE_SIZE = 100
922
-
923
- if self.stop is not None:
924
- limit = self.stop - self.start
925
- else:
926
- limit = None
927
-
928
- use_scroll = limit is None or limit > PAGE_SIZE
929
-
930
- body = self._get_es_body()
931
- params = {
932
- "index": self.backend.get_index_for_model(
933
- self.query_compiler.queryset.model
934
- ).name,
935
- "_source": False,
936
- self.fields_param_name: "pk",
937
- }
938
-
939
- if use_scroll:
940
- params.update(
941
- {
942
- "scroll": "2m",
943
- "size": PAGE_SIZE,
944
- }
945
- )
946
-
947
- # The scroll API doesn't support offset, manually skip the first results
948
- skip = self.start
949
-
950
- # Send to Elasticsearch
951
- page = self._backend_do_search(body, **params)
952
-
953
- while True:
954
- hits = page["hits"]["hits"]
955
-
956
- if len(hits) == 0:
957
- break
958
-
959
- # Get results
960
- if skip < len(hits):
961
- for result in self._get_results_from_hits(hits):
962
- if limit is not None and limit == 0:
963
- break
964
-
965
- if skip == 0:
966
- yield result
967
-
968
- if limit is not None:
969
- limit -= 1
970
- else:
971
- skip -= 1
972
-
973
- if limit is not None and limit == 0:
974
- break
975
- else:
976
- # Skip whole page
977
- skip -= len(hits)
978
-
979
- # Fetch next page of results
980
- if "_scroll_id" not in page:
981
- break
982
-
983
- page = self.backend.es.scroll(scroll_id=page["_scroll_id"], scroll="2m")
984
-
985
- # Clear the scroll
986
- if "_scroll_id" in page:
987
- self.backend.es.clear_scroll(scroll_id=page["_scroll_id"])
988
- else:
989
- params.update(
990
- {
991
- "from_": self.start,
992
- "size": limit or PAGE_SIZE,
993
- }
994
- )
995
-
996
- # Send to Elasticsearch
997
- hits = self._backend_do_search(body, **params)["hits"]["hits"]
998
-
999
- # Get results
1000
- for result in self._get_results_from_hits(hits):
1001
- yield result
1002
-
1003
- def _do_count(self):
1004
- # Get count
1005
- hit_count = self.backend.es.count(
1006
- index=self.backend.get_index_for_model(
1007
- self.query_compiler.queryset.model
1008
- ).name,
1009
- body=self._get_es_body(for_count=True),
1010
- )["count"]
1011
-
1012
- # Add limits
1013
- hit_count -= self.start
1014
- if self.stop is not None:
1015
- hit_count = min(hit_count, self.stop - self.start)
1016
-
1017
- return max(hit_count, 0)
1018
-
1019
-
1020
- class ElasticsearchAutocompleteQueryCompilerImpl:
1021
- def __init__(self, *args, **kwargs):
1022
- super().__init__(*args, **kwargs)
1023
-
1024
- # Convert field names into index column names
1025
- # Note: this overrides Elasticsearch7SearchQueryCompiler by using autocomplete fields instead of searchable fields
1026
- if self.fields:
1027
- fields = []
1028
- autocomplete_fields = {
1029
- f.field_name: f
1030
- for f in self.queryset.model.get_autocomplete_search_fields()
1031
- }
1032
- for field_name in self.fields:
1033
- if field_name in autocomplete_fields:
1034
- field_name = self.mapping.get_field_column_name(
1035
- autocomplete_fields[field_name]
1036
- )
1037
11
 
1038
- fields.append(field_name)
12
+ from wagtail.search.backends.deprecation import (
13
+ IndexOptionMixin,
14
+ LegacyContentTypeMatchMixin,
15
+ )
1039
16
 
1040
- self.remapped_fields = fields
1041
- else:
1042
- self.remapped_fields = None
1043
17
 
1044
- def get_inner_query(self):
1045
- fields = self.remapped_fields or [self.mapping.edgengrams_field_name]
1046
- fields = [Field(field) for field in fields]
1047
- if len(fields) == 0:
1048
- # No fields. Return a query that'll match nothing
1049
- return {"bool": {"mustNot": {"match_all": {}}}}
1050
- elif isinstance(self.query, PlainText):
1051
- return self._compile_plaintext_query(self.query, fields)
1052
- elif isinstance(self.query, MatchAll):
1053
- return {"match_all": {}}
1054
- else:
1055
- raise NotImplementedError(
1056
- "`%s` is not supported for autocomplete queries."
1057
- % self.query.__class__.__name__
1058
- )
18
+ class Elasticsearch7SearchQueryCompiler(
19
+ LegacyContentTypeMatchMixin, _Elasticsearch7SearchQueryCompiler
20
+ ):
21
+ pass
1059
22
 
1060
23
 
1061
24
  class Elasticsearch7AutocompleteQueryCompiler(
1062
- ElasticsearchAutocompleteQueryCompilerImpl, Elasticsearch7SearchQueryCompiler
25
+ LegacyContentTypeMatchMixin, _Elasticsearch7AutocompleteQueryCompiler
1063
26
  ):
1064
27
  pass
1065
28
 
1066
29
 
1067
- class ElasticsearchIndexRebuilder:
1068
- def __init__(self, index):
1069
- self.index = index
1070
-
1071
- def reset_index(self):
1072
- self.index.reset()
1073
-
1074
- def start(self):
1075
- # Reset the index
1076
- self.reset_index()
1077
-
1078
- return self.index
1079
-
1080
- def finish(self):
1081
- self.index.refresh()
1082
-
1083
-
1084
- class ElasticsearchAtomicIndexRebuilder(ElasticsearchIndexRebuilder):
1085
- def __init__(self, index):
1086
- self.alias = index
1087
- self.index = index.backend.index_class(
1088
- index.backend, self.alias.name + "_" + get_random_string(7).lower()
1089
- )
1090
-
1091
- def reset_index(self):
1092
- # Delete old index using the alias
1093
- # This should delete both the alias and the index
1094
- self.alias.delete()
1095
-
1096
- # Create new index
1097
- self.index.put()
1098
-
1099
- # Create a new alias
1100
- self.index.put_alias(self.alias.name)
1101
-
1102
- def start(self):
1103
- # Create the new index
1104
- self.index.put()
1105
-
1106
- return self.index
1107
-
1108
- def finish(self):
1109
- self.index.refresh()
1110
-
1111
- if self.alias.is_alias():
1112
- # Update existing alias, then delete the old index
1113
-
1114
- # Find index that alias currently points to, we'll delete it after
1115
- # updating the alias
1116
- old_index = self.alias.aliased_indices()
1117
-
1118
- # Update alias to point to new index
1119
- self.index.put_alias(self.alias.name)
1120
-
1121
- # Delete old index
1122
- # aliased_indices() can return multiple indices. Delete them all
1123
- for index in old_index:
1124
- if index.name != self.index.name:
1125
- index.delete()
1126
-
1127
- else:
1128
- # self.alias doesn't currently refer to an alias in Elasticsearch.
1129
- # This means that either nothing exists in ES with that name or
1130
- # there is currently an index with the that name
1131
-
1132
- # Run delete on the alias, just in case it is currently an index.
1133
- # This happens on the first rebuild after switching ATOMIC_REBUILD on
1134
- self.alias.delete()
1135
-
1136
- # Create the alias
1137
- self.index.put_alias(self.alias.name)
1138
-
1139
-
1140
- class Elasticsearch7SearchBackend(BaseSearchBackend):
1141
- mapping_class = Elasticsearch7Mapping
1142
- index_class = Elasticsearch7Index
30
+ class Elasticsearch7SearchBackend(IndexOptionMixin, _Elasticsearch7SearchBackend):
1143
31
  query_compiler_class = Elasticsearch7SearchQueryCompiler
1144
32
  autocomplete_query_compiler_class = Elasticsearch7AutocompleteQueryCompiler
1145
- results_class = Elasticsearch7SearchResults
1146
- basic_rebuilder_class = ElasticsearchIndexRebuilder
1147
- atomic_rebuilder_class = ElasticsearchAtomicIndexRebuilder
1148
- catch_indexing_errors = True
1149
- timeout_kwarg_name = "timeout"
1150
-
1151
- settings = {
1152
- "settings": {
1153
- "analysis": {
1154
- "analyzer": {
1155
- "ngram_analyzer": {
1156
- "type": "custom",
1157
- "tokenizer": "standard",
1158
- "filter": ["asciifolding", "lowercase", "ngram"],
1159
- },
1160
- "edgengram_analyzer": {
1161
- "type": "custom",
1162
- "tokenizer": "standard",
1163
- "filter": ["asciifolding", "lowercase", "edgengram"],
1164
- },
1165
- },
1166
- "tokenizer": {
1167
- "ngram_tokenizer": {
1168
- "type": "ngram",
1169
- "min_gram": 3,
1170
- "max_gram": 15,
1171
- },
1172
- "edgengram_tokenizer": {
1173
- "type": "edge_ngram",
1174
- "min_gram": 2,
1175
- "max_gram": 15,
1176
- "side": "front",
1177
- },
1178
- },
1179
- "filter": {
1180
- "ngram": {"type": "ngram", "min_gram": 3, "max_gram": 15},
1181
- "edgengram": {"type": "edge_ngram", "min_gram": 1, "max_gram": 15},
1182
- },
1183
- },
1184
- "index": {
1185
- "max_ngram_diff": 12,
1186
- },
1187
- }
1188
- }
1189
-
1190
- def _get_host_config_from_url(self, url):
1191
- """Given a parsed URL, return the host configuration to be added to self.hosts"""
1192
- use_ssl = url.scheme == "https"
1193
- port = url.port or (443 if use_ssl else 80)
1194
-
1195
- http_auth = None
1196
- if url.username is not None and url.password is not None:
1197
- http_auth = (url.username, url.password)
1198
-
1199
- return {
1200
- "host": url.hostname,
1201
- "port": port,
1202
- "url_prefix": url.path,
1203
- "use_ssl": use_ssl,
1204
- "verify_certs": use_ssl,
1205
- "http_auth": http_auth,
1206
- }
1207
-
1208
- def _get_options_from_host_urls(self, urls):
1209
- """Given a list of parsed URLs, return a dict of additional options to be passed into the
1210
- Elasticsearch constructor; necessary for options that aren't valid as part of the 'hosts' config
1211
- """
1212
- return {}
1213
-
1214
- def __init__(self, params):
1215
- super().__init__(params)
1216
-
1217
- # Get settings
1218
- self.hosts = params.pop("HOSTS", None)
1219
- self.index_name = params.pop("INDEX", "wagtail")
1220
- self.timeout = params.pop("TIMEOUT", 10)
1221
-
1222
- if params.pop("ATOMIC_REBUILD", False):
1223
- self.rebuilder_class = self.atomic_rebuilder_class
1224
- else:
1225
- self.rebuilder_class = self.basic_rebuilder_class
1226
-
1227
- self.settings = deepcopy(
1228
- self.settings
1229
- ) # Make the class settings attribute as instance settings attribute
1230
- self.settings = deep_update(self.settings, params.pop("INDEX_SETTINGS", {}))
1231
-
1232
- # Get Elasticsearch interface
1233
- # Any remaining params are passed into the Elasticsearch constructor
1234
- options = params.pop("OPTIONS", {})
1235
-
1236
- # If HOSTS is not set, convert URLS setting to HOSTS
1237
- if self.hosts is None:
1238
- es_urls = params.pop("URLS", ["http://localhost:9200"])
1239
- # if es_urls is not a list, convert it to a list
1240
- if isinstance(es_urls, str):
1241
- es_urls = [es_urls]
1242
-
1243
- parsed_urls = [urlparse(url) for url in es_urls]
1244
-
1245
- self.hosts = [self._get_host_config_from_url(url) for url in parsed_urls]
1246
- options.update(self._get_options_from_host_urls(parsed_urls))
1247
-
1248
- options[self.timeout_kwarg_name] = self.timeout
1249
-
1250
- self.es = Elasticsearch(hosts=self.hosts, **options)
1251
-
1252
- def get_index_for_model(self, model):
1253
- # Split models up into separate indices based on their root model.
1254
- # For example, all page-derived models get put together in one index,
1255
- # while images and documents each have their own index.
1256
- root_model = get_model_root(model)
1257
- index_suffix = (
1258
- "__"
1259
- + root_model._meta.app_label.lower()
1260
- + "_"
1261
- + root_model.__name__.lower()
1262
- )
1263
-
1264
- return self.index_class(self, self.index_name + index_suffix)
1265
-
1266
- def get_index(self):
1267
- return self.index_class(self, self.index_name)
1268
-
1269
- def get_rebuilder(self):
1270
- return self.rebuilder_class(self.get_index())
1271
-
1272
- def reset_index(self):
1273
- # Use the rebuilder to reset the index
1274
- self.get_rebuilder().reset_index()
1275
33
 
1276
34
 
1277
35
  SearchBackend = Elasticsearch7SearchBackend