codex 1.6.19__py3-none-any.whl → 1.7.0a0__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.

Potentially problematic release.


This version of codex might be problematic. Click here for more details.

Files changed (576) hide show
  1. codex/db.py +119 -0
  2. codex/librarian/covers/purge.py +1 -1
  3. codex/librarian/importer/const.py +7 -1
  4. codex/librarian/importer/create_fks.py +5 -2
  5. codex/librarian/importer/importerd.py +17 -12
  6. codex/librarian/importer/moved.py +44 -13
  7. codex/librarian/importer/tasks.py +2 -0
  8. codex/librarian/janitor/cleanup.py +21 -8
  9. codex/librarian/janitor/integrity.py +369 -0
  10. codex/librarian/janitor/janitor.py +50 -15
  11. codex/librarian/janitor/latest_version.py +2 -1
  12. codex/librarian/janitor/status.py +5 -0
  13. codex/librarian/janitor/tasks.py +37 -0
  14. codex/librarian/janitor/update.py +1 -1
  15. codex/librarian/librariand.py +32 -24
  16. codex/librarian/search/optimize.py +43 -0
  17. codex/librarian/search/remove.py +18 -46
  18. codex/librarian/search/searchd.py +14 -17
  19. codex/librarian/search/status.py +2 -1
  20. codex/librarian/search/tasks.py +4 -9
  21. codex/librarian/search/update.py +223 -301
  22. codex/librarian/watchdog/observers.py +2 -1
  23. codex/migrations/0029_comicfts.py +58 -0
  24. codex/migrations/0030_nocase_collation_day_month_indexes_status_types.py +198 -0
  25. codex/models/admin.py +15 -6
  26. codex/models/base.py +9 -0
  27. codex/models/bookmark.py +3 -3
  28. codex/models/comic.py +68 -16
  29. codex/models/functions.py +59 -2
  30. codex/models/groups.py +6 -1
  31. codex/models/library.py +1 -3
  32. codex/models/paths.py +9 -3
  33. codex/serializers/browser/page.py +2 -0
  34. codex/settings/settings.py +16 -17
  35. codex/signals/django_signals.py +4 -10
  36. codex/startup.py +1 -35
  37. codex/static_root/assets/{VCheckbox-Cko1sQK-.170726b3b8a1.js → VCheckbox-CWiqcZ7a.3feebd47daab.js} +1 -1
  38. codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js.br +0 -0
  39. codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js.gz +0 -0
  40. codex/static_root/assets/{VCheckbox-Cko1sQK-.js → VCheckbox-CWiqcZ7a.js} +1 -1
  41. codex/static_root/assets/VCheckbox-CWiqcZ7a.js.br +0 -0
  42. codex/static_root/assets/VCheckbox-CWiqcZ7a.js.gz +0 -0
  43. codex/static_root/assets/{VCheckboxBtn-CO3-aqQL.c9b8062fd66f.js → VCheckboxBtn-Dk3iB62X.bc66d5351baa.js} +1 -1
  44. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js.br +0 -0
  45. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js.gz +0 -0
  46. codex/static_root/assets/{VCheckboxBtn-CO3-aqQL.js → VCheckboxBtn-Dk3iB62X.js} +1 -1
  47. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js.br +0 -0
  48. codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js.gz +0 -0
  49. codex/static_root/assets/{VCombobox-Bjp6lffE.js → VCombobox-D1_KU27A.b1d30587a973.js} +1 -1
  50. codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js.br +0 -0
  51. codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js.gz +0 -0
  52. codex/static_root/assets/{VCombobox-Bjp6lffE.caf59fba486e.js → VCombobox-D1_KU27A.js} +1 -1
  53. codex/static_root/assets/VCombobox-D1_KU27A.js.br +0 -0
  54. codex/static_root/assets/VCombobox-D1_KU27A.js.gz +0 -0
  55. codex/static_root/assets/{VDialog-BkpVGB70.6eea3ca762a5.js → VDialog-GbxvFMMN.594fb3a39ced.js} +1 -1
  56. codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js.br +0 -0
  57. codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js.gz +0 -0
  58. codex/static_root/assets/{VDialog-BkpVGB70.js → VDialog-GbxvFMMN.js} +1 -1
  59. codex/static_root/assets/VDialog-GbxvFMMN.js.br +0 -0
  60. codex/static_root/assets/VDialog-GbxvFMMN.js.gz +0 -0
  61. codex/static_root/assets/{VExpansionPanels-Ci2-j8XX.9c55db4ef49e.js → VExpansionPanels-Cywv_bEj.a762e63858e5.js} +1 -1
  62. codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js.br +0 -0
  63. codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js.gz +0 -0
  64. codex/static_root/assets/{VExpansionPanels-Ci2-j8XX.js → VExpansionPanels-Cywv_bEj.js} +1 -1
  65. codex/static_root/assets/VExpansionPanels-Cywv_bEj.js.br +0 -0
  66. codex/static_root/assets/VExpansionPanels-Cywv_bEj.js.gz +0 -0
  67. codex/static_root/assets/{VRadioGroup-D3Py5BfQ.a4f25edb86d3.js → VRadioGroup-C0etmxpZ.0eb3009a6300.js} +1 -1
  68. codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js.br +0 -0
  69. codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js.gz +0 -0
  70. codex/static_root/assets/{VRadioGroup-D3Py5BfQ.js → VRadioGroup-C0etmxpZ.js} +1 -1
  71. codex/static_root/assets/VRadioGroup-C0etmxpZ.js.br +0 -0
  72. codex/static_root/assets/VRadioGroup-C0etmxpZ.js.gz +0 -0
  73. codex/static_root/assets/{VSelect-DtvZsYZz.e98745d858eb.js → VSelect-txrnRiNJ.a5625760018c.js} +1 -1
  74. codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js.br +0 -0
  75. codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js.gz +0 -0
  76. codex/static_root/assets/{VSelect-DtvZsYZz.js → VSelect-txrnRiNJ.js} +1 -1
  77. codex/static_root/assets/VSelect-txrnRiNJ.js.br +0 -0
  78. codex/static_root/assets/VSelect-txrnRiNJ.js.gz +0 -0
  79. codex/static_root/assets/{VSelectionControl-D6kmykQW.1e1fda62ceba.js → VSelectionControl-CY6RmcvW.7e8824224f6c.js} +1 -1
  80. codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js.br +0 -0
  81. codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js.gz +0 -0
  82. codex/static_root/assets/{VSelectionControl-D6kmykQW.js → VSelectionControl-CY6RmcvW.js} +1 -1
  83. codex/static_root/assets/VSelectionControl-CY6RmcvW.js.br +0 -0
  84. codex/static_root/assets/VSelectionControl-CY6RmcvW.js.gz +0 -0
  85. codex/static_root/assets/{VSlideGroup-UGZWxpF5.360bdefcd215.js → VSlideGroup-DtEQMwY1.6c72325635ed.js} +1 -1
  86. codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js.br +0 -0
  87. codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js.gz +0 -0
  88. codex/static_root/assets/{VSlideGroup-UGZWxpF5.js → VSlideGroup-DtEQMwY1.js} +1 -1
  89. codex/static_root/assets/VSlideGroup-DtEQMwY1.js.br +0 -0
  90. codex/static_root/assets/VSlideGroup-DtEQMwY1.js.gz +0 -0
  91. codex/static_root/assets/{VTable-DXH_yQ0o.1149f56ad566.js → VTable-2af995xo.6c5bf36631b2.js} +1 -1
  92. codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js.br +0 -0
  93. codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js.gz +0 -0
  94. codex/static_root/assets/{VTable-DXH_yQ0o.js → VTable-2af995xo.js} +1 -1
  95. codex/static_root/assets/VTable-2af995xo.js.br +0 -0
  96. codex/static_root/assets/VTable-2af995xo.js.gz +0 -0
  97. codex/static_root/assets/{VTextField-Blqy56_L.26d8761e0155.js → VTextField-G6CMj7yO.657a130dd302.js} +1 -1
  98. codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js.br +0 -0
  99. codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js.gz +0 -0
  100. codex/static_root/assets/{VTextField-Blqy56_L.js → VTextField-G6CMj7yO.js} +1 -1
  101. codex/static_root/assets/VTextField-G6CMj7yO.js.br +0 -0
  102. codex/static_root/assets/VTextField-G6CMj7yO.js.gz +0 -0
  103. codex/static_root/assets/{VWindowItem-C8_ovV7e.afbc08414765.js → VWindowItem-CzoGd6Ul.721e5da11ad4.js} +1 -1
  104. codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js.br +0 -0
  105. codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js.gz +0 -0
  106. codex/static_root/assets/{VWindowItem-C8_ovV7e.js → VWindowItem-CzoGd6Ul.js} +1 -1
  107. codex/static_root/assets/VWindowItem-CzoGd6Ul.js.br +0 -0
  108. codex/static_root/assets/VWindowItem-CzoGd6Ul.js.gz +0 -0
  109. codex/static_root/assets/{admin-DTRn8bBs.d031ea42d8d0.js → admin-CsPAIQeG.5175467148a3.js} +1 -1
  110. codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js.br +0 -0
  111. codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js.gz +0 -0
  112. codex/static_root/assets/{admin-DTRn8bBs.js → admin-CsPAIQeG.js} +1 -1
  113. codex/static_root/assets/admin-CsPAIQeG.js.br +0 -0
  114. codex/static_root/assets/admin-CsPAIQeG.js.gz +0 -0
  115. codex/static_root/assets/{admin-drawer-panel-BaXFOcru.b1a44b05f482.js → admin-drawer-panel-BAT7GA64.73a064628c19.js} +11 -11
  116. codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js.br +0 -0
  117. codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js.gz +0 -0
  118. codex/static_root/assets/{admin-drawer-panel-BaXFOcru.js → admin-drawer-panel-BAT7GA64.js} +11 -11
  119. codex/static_root/assets/admin-drawer-panel-BAT7GA64.js.br +0 -0
  120. codex/static_root/assets/admin-drawer-panel-BAT7GA64.js.gz +0 -0
  121. codex/static_root/assets/browser-C18l93yc.923860009ef4.js +1 -0
  122. codex/static_root/assets/browser-C18l93yc.923860009ef4.js.br +0 -0
  123. codex/static_root/assets/browser-C18l93yc.923860009ef4.js.gz +0 -0
  124. codex/static_root/assets/browser-C18l93yc.js +1 -0
  125. codex/static_root/assets/browser-C18l93yc.js.br +0 -0
  126. codex/static_root/assets/browser-C18l93yc.js.gz +0 -0
  127. codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css +1 -0
  128. codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css.br +0 -0
  129. codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css.gz +0 -0
  130. codex/static_root/assets/browser-DaAqlBYO.css +1 -0
  131. codex/static_root/assets/browser-DaAqlBYO.css.br +0 -0
  132. codex/static_root/assets/browser-DaAqlBYO.css.gz +0 -0
  133. codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js +1 -0
  134. codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js.br +0 -0
  135. codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js.gz +0 -0
  136. codex/static_root/assets/change-password-dialog-BazJdNs9.js +1 -0
  137. codex/static_root/assets/change-password-dialog-BazJdNs9.js.br +0 -0
  138. codex/static_root/assets/change-password-dialog-BazJdNs9.js.gz +0 -0
  139. codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css +1 -0
  140. codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css.br +0 -0
  141. codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css.gz +0 -0
  142. codex/static_root/assets/change-password-dialog-Mlmvz8_4.css +1 -0
  143. codex/static_root/assets/change-password-dialog-Mlmvz8_4.css.br +0 -0
  144. codex/static_root/assets/change-password-dialog-Mlmvz8_4.css.gz +0 -0
  145. codex/static_root/assets/{confirm-dialog-D3_s2DQy.9dde66036c72.js → confirm-dialog-CbW3hlOp.9dd39b443c31.js} +1 -1
  146. codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js.br +0 -0
  147. codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js.gz +0 -0
  148. codex/static_root/assets/{confirm-dialog-D3_s2DQy.js → confirm-dialog-CbW3hlOp.js} +1 -1
  149. codex/static_root/assets/confirm-dialog-CbW3hlOp.js.br +0 -0
  150. codex/static_root/assets/confirm-dialog-CbW3hlOp.js.gz +0 -0
  151. codex/static_root/assets/{datetime-column-BxC1Li9e.3dc314b3295d.js → datetime-column-uSqKZU37.b157b0743db5.js} +1 -1
  152. codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js.br +0 -0
  153. codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js.gz +0 -0
  154. codex/static_root/assets/{datetime-column-BxC1Li9e.js → datetime-column-uSqKZU37.js} +1 -1
  155. codex/static_root/assets/datetime-column-uSqKZU37.js.br +0 -0
  156. codex/static_root/assets/datetime-column-uSqKZU37.js.gz +0 -0
  157. codex/static_root/assets/{filter-Bzk7x841.d0c3b602e62d.js → filter-CBl5KEsB.845a81573c2e.js} +1 -1
  158. codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js.br +0 -0
  159. codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js.gz +0 -0
  160. codex/static_root/assets/{filter-Bzk7x841.js → filter-CBl5KEsB.js} +1 -1
  161. codex/static_root/assets/filter-CBl5KEsB.js.br +0 -0
  162. codex/static_root/assets/filter-CBl5KEsB.js.gz +0 -0
  163. codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js +1 -0
  164. codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js.br +0 -0
  165. codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js.gz +0 -0
  166. codex/static_root/assets/flag-tab-CT8pqM4r.js +1 -0
  167. codex/static_root/assets/flag-tab-CT8pqM4r.js.br +0 -0
  168. codex/static_root/assets/flag-tab-CT8pqM4r.js.gz +0 -0
  169. codex/static_root/assets/{group-tab-5esH4lwX.a81fdd258117.js → group-tab-BOW9kigw.7e5007596367.js} +1 -1
  170. codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js.br +0 -0
  171. codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js.gz +0 -0
  172. codex/static_root/assets/{group-tab-5esH4lwX.js → group-tab-BOW9kigw.js} +1 -1
  173. codex/static_root/assets/group-tab-BOW9kigw.js.br +0 -0
  174. codex/static_root/assets/group-tab-BOW9kigw.js.gz +0 -0
  175. codex/static_root/assets/{http-error-BTOBfcGY.52ced6f28420.js → http-error-C6yuLApo.45cf99eb7a70.js} +1 -1
  176. codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.br +4 -0
  177. codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.gz +0 -0
  178. codex/static_root/assets/{http-error-BTOBfcGY.js → http-error-C6yuLApo.js} +1 -1
  179. codex/static_root/assets/http-error-C6yuLApo.js.br +4 -0
  180. codex/static_root/assets/http-error-C6yuLApo.js.gz +0 -0
  181. codex/static_root/assets/{library-tab-DiPEdOF7.ece2d642a9dc.js → library-tab-D3WOtpE0.9af34e6e7235.js} +1 -1
  182. codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js.br +0 -0
  183. codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js.gz +0 -0
  184. codex/static_root/assets/{library-tab-DiPEdOF7.js → library-tab-D3WOtpE0.js} +1 -1
  185. codex/static_root/assets/library-tab-D3WOtpE0.js.br +0 -0
  186. codex/static_root/assets/library-tab-D3WOtpE0.js.gz +0 -0
  187. codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js +6 -0
  188. codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js.br +0 -0
  189. codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js.gz +0 -0
  190. codex/static_root/assets/main-CmjU2oTp.js +6 -0
  191. codex/static_root/assets/main-CmjU2oTp.js.br +0 -0
  192. codex/static_root/assets/main-CmjU2oTp.js.gz +0 -0
  193. codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js +1 -0
  194. codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js.br +0 -0
  195. codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js.gz +0 -0
  196. codex/static_root/assets/pager-full-pdf-BH54_5f6.js +1 -0
  197. codex/static_root/assets/pager-full-pdf-BH54_5f6.js.br +0 -0
  198. codex/static_root/assets/pager-full-pdf-BH54_5f6.js.gz +0 -0
  199. codex/static_root/assets/{pagination-toolbar-C45-onwe.4722195bb60b.css → pagination-toolbar-DGrxp2OD.css} +1 -1
  200. codex/static_root/assets/pagination-toolbar-DGrxp2OD.css.br +0 -0
  201. codex/static_root/assets/pagination-toolbar-DGrxp2OD.css.gz +0 -0
  202. codex/static_root/assets/{pagination-toolbar-C45-onwe.css → pagination-toolbar-DGrxp2OD.f960a624f04f.css} +1 -1
  203. codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css.br +0 -0
  204. codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css.gz +0 -0
  205. codex/static_root/assets/{pagination-toolbar-CkIzuyx1.00c354a82e6e.js → pagination-toolbar-JH3Kbffr.451171f7ac33.js} +1 -1
  206. codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js.br +0 -0
  207. codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js.gz +0 -0
  208. codex/static_root/assets/{pagination-toolbar-CkIzuyx1.js → pagination-toolbar-JH3Kbffr.js} +1 -1
  209. codex/static_root/assets/pagination-toolbar-JH3Kbffr.js.br +0 -0
  210. codex/static_root/assets/pagination-toolbar-JH3Kbffr.js.gz +0 -0
  211. codex/static_root/assets/{pdf-doc-BjlRPuf4.0f056fa321b6.js → pdf-doc-BcRNpoaW.882f6e967869.js} +1 -1
  212. codex/static_root/assets/pdf-doc-BcRNpoaW.882f6e967869.js.br +0 -0
  213. codex/static_root/assets/pdf-doc-BcRNpoaW.882f6e967869.js.gz +0 -0
  214. codex/static_root/assets/{pdf-doc-BjlRPuf4.js → pdf-doc-BcRNpoaW.js} +1 -1
  215. codex/static_root/assets/pdf-doc-BcRNpoaW.js.br +0 -0
  216. codex/static_root/assets/pdf-doc-BcRNpoaW.js.gz +0 -0
  217. codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js +2 -0
  218. codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js.br +0 -0
  219. codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js.gz +0 -0
  220. codex/static_root/assets/reader-DIPRg2VB.js +2 -0
  221. codex/static_root/assets/reader-DIPRg2VB.js.br +0 -0
  222. codex/static_root/assets/reader-DIPRg2VB.js.gz +0 -0
  223. codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css +1 -0
  224. codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css.br +0 -0
  225. codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css.gz +0 -0
  226. codex/static_root/assets/reader-DveZZr9x.css +1 -0
  227. codex/static_root/assets/reader-DveZZr9x.css.br +0 -0
  228. codex/static_root/assets/reader-DveZZr9x.css.gz +0 -0
  229. codex/static_root/assets/{relation-chips-CUSatZET.js → relation-chips-3tTlR5QH.71f18bc92adc.js} +1 -1
  230. codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js.br +0 -0
  231. codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js.gz +0 -0
  232. codex/static_root/assets/{relation-chips-CUSatZET.a58031ff8141.js → relation-chips-3tTlR5QH.js} +1 -1
  233. codex/static_root/assets/relation-chips-3tTlR5QH.js.br +0 -0
  234. codex/static_root/assets/relation-chips-3tTlR5QH.js.gz +0 -0
  235. codex/static_root/assets/{settings-drawer-BSHTAsJ9.js → settings-drawer-BdyFhA_r.151f4c3061ed.js} +2 -2
  236. codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js.br +0 -0
  237. codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js.gz +0 -0
  238. codex/static_root/assets/{settings-drawer-BSHTAsJ9.1d07ce084fc9.js → settings-drawer-BdyFhA_r.js} +2 -2
  239. codex/static_root/assets/settings-drawer-BdyFhA_r.js.br +0 -0
  240. codex/static_root/assets/settings-drawer-BdyFhA_r.js.gz +0 -0
  241. codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js +1 -0
  242. codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js.br +0 -0
  243. codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js.gz +0 -0
  244. codex/static_root/assets/stats-tab-DeKjwvmh.js +1 -0
  245. codex/static_root/assets/stats-tab-DeKjwvmh.js.br +0 -0
  246. codex/static_root/assets/stats-tab-DeKjwvmh.js.gz +0 -0
  247. codex/static_root/assets/{stats-tab-BXGisn5N.9b7a71e7fe28.css → stats-tab-DpfGsVX3.1cb66f2649a9.css} +1 -1
  248. codex/static_root/assets/stats-tab-DpfGsVX3.1cb66f2649a9.css.br +0 -0
  249. codex/static_root/assets/stats-tab-DpfGsVX3.1cb66f2649a9.css.gz +0 -0
  250. codex/static_root/assets/{stats-tab-BXGisn5N.css → stats-tab-DpfGsVX3.css} +1 -1
  251. codex/static_root/assets/stats-tab-DpfGsVX3.css.br +0 -0
  252. codex/static_root/assets/stats-tab-DpfGsVX3.css.gz +0 -0
  253. codex/static_root/assets/{task-tab-NORFAa9p.97e07e366ddd.js → task-tab-C8D0qRP_.d4ab174c69a3.js} +1 -1
  254. codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js.br +0 -0
  255. codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js.gz +0 -0
  256. codex/static_root/assets/{task-tab-NORFAa9p.js → task-tab-C8D0qRP_.js} +1 -1
  257. codex/static_root/assets/task-tab-C8D0qRP_.js.br +0 -0
  258. codex/static_root/assets/task-tab-C8D0qRP_.js.gz +0 -0
  259. codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js +1 -0
  260. codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js.br +0 -0
  261. codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js.gz +0 -0
  262. codex/static_root/assets/unauthorized-BHgBRF4z.js +1 -0
  263. codex/static_root/assets/unauthorized-BHgBRF4z.js.br +0 -0
  264. codex/static_root/assets/unauthorized-BHgBRF4z.js.gz +0 -0
  265. codex/static_root/assets/{unauthorized-muDsv-rC.css → unauthorized-BjhIc97q.728511c92cd0.css} +1 -1
  266. codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css.br +0 -0
  267. codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css.gz +0 -0
  268. codex/static_root/assets/{unauthorized-muDsv-rC.2166ec8b3a32.css → unauthorized-BjhIc97q.css} +1 -1
  269. codex/static_root/assets/unauthorized-BjhIc97q.css.br +0 -0
  270. codex/static_root/assets/unauthorized-BjhIc97q.css.gz +0 -0
  271. codex/static_root/assets/{user-tab-CHbyN1EW.e7206db08680.js → user-tab-BU31Z92y.35613c713faf.js} +1 -1
  272. codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js.br +0 -0
  273. codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js.gz +0 -0
  274. codex/static_root/assets/{user-tab-CHbyN1EW.js → user-tab-BU31Z92y.js} +1 -1
  275. codex/static_root/assets/user-tab-BU31Z92y.js.br +0 -0
  276. codex/static_root/assets/user-tab-BU31Z92y.js.gz +0 -0
  277. codex/static_root/js/choices-admin.8aa64c911203.json +1 -0
  278. codex/static_root/js/choices-admin.8aa64c911203.json.br +0 -0
  279. codex/static_root/js/choices-admin.8aa64c911203.json.gz +0 -0
  280. codex/static_root/js/choices-admin.json +1 -1
  281. codex/static_root/js/choices-admin.json.br +0 -0
  282. codex/static_root/js/choices-admin.json.gz +0 -0
  283. codex/static_root/manifest.45cb46e19686.json +635 -0
  284. codex/static_root/manifest.45cb46e19686.json.br +0 -0
  285. codex/static_root/manifest.45cb46e19686.json.gz +0 -0
  286. codex/static_root/manifest.json +248 -248
  287. codex/static_root/manifest.json.br +0 -0
  288. codex/static_root/manifest.json.gz +0 -0
  289. codex/static_root/staticfiles.json +1 -1
  290. codex/status_controller.py +10 -4
  291. codex/views/admin/tasks.py +46 -40
  292. codex/views/auth.py +15 -4
  293. codex/views/browser/annotations.py +94 -51
  294. codex/views/browser/base.py +1 -2
  295. codex/views/browser/browser.py +52 -21
  296. codex/views/browser/cover.py +8 -4
  297. codex/views/browser/filters/annotations.py +28 -6
  298. codex/views/browser/filters/search/__init__.py +1 -0
  299. codex/views/browser/filters/search/aliases.py +81 -0
  300. codex/views/browser/filters/search/field/__init__.py +1 -0
  301. codex/views/browser/filters/search/field/column.py +53 -0
  302. codex/views/browser/filters/search/field/expression.py +177 -0
  303. codex/views/browser/filters/search/field/filter.py +70 -0
  304. codex/views/browser/filters/search/field/optimize.py +71 -0
  305. codex/views/browser/filters/search/field/parse.py +187 -0
  306. codex/views/browser/filters/search/fts.py +38 -0
  307. codex/views/browser/filters/search/parse.py +220 -0
  308. codex/views/browser/order_by.py +8 -2
  309. codex/views/browser/page_in_bounds.py +88 -0
  310. codex/views/browser/paginate.py +28 -113
  311. codex/views/const.py +0 -1
  312. codex/views/opds/v1/feed.py +2 -1
  313. codex/views/opds/v2/feed.py +2 -1
  314. codex/views/opds/v2/links.py +1 -1
  315. codex/views/reader/books.py +1 -1
  316. codex/views/reader/page.py +3 -3
  317. {codex-1.6.19.dist-info → codex-1.7.0a0.dist-info}/METADATA +18 -10
  318. {codex-1.6.19.dist-info → codex-1.7.0a0.dist-info}/RECORD +321 -372
  319. codex/_vendor/__init__.py +0 -0
  320. codex/_vendor/django_haystack-3.2.1.dist-info/AUTHORS +0 -127
  321. codex/_vendor/django_haystack-3.2.1.dist-info/INSTALLER +0 -1
  322. codex/_vendor/django_haystack-3.2.1.dist-info/LICENSE +0 -31
  323. codex/_vendor/django_haystack-3.2.1.dist-info/METADATA +0 -98
  324. codex/_vendor/django_haystack-3.2.1.dist-info/RECORD +0 -97
  325. codex/_vendor/django_haystack-3.2.1.dist-info/REQUESTED +0 -0
  326. codex/_vendor/django_haystack-3.2.1.dist-info/WHEEL +0 -5
  327. codex/_vendor/django_haystack-3.2.1.dist-info/top_level.txt +0 -1
  328. codex/_vendor/haystack/__init__.py +0 -80
  329. codex/_vendor/haystack/admin.py +0 -163
  330. codex/_vendor/haystack/apps.py +0 -31
  331. codex/_vendor/haystack/backends/__init__.py +0 -1109
  332. codex/_vendor/haystack/backends/elasticsearch2_backend.py +0 -390
  333. codex/_vendor/haystack/backends/elasticsearch5_backend.py +0 -483
  334. codex/_vendor/haystack/backends/elasticsearch7_backend.py +0 -586
  335. codex/_vendor/haystack/backends/elasticsearch_backend.py +0 -1141
  336. codex/_vendor/haystack/backends/simple_backend.py +0 -132
  337. codex/_vendor/haystack/backends/solr_backend.py +0 -991
  338. codex/_vendor/haystack/backends/whoosh_backend.py +0 -1104
  339. codex/_vendor/haystack/constants.py +0 -57
  340. codex/_vendor/haystack/exceptions.py +0 -57
  341. codex/_vendor/haystack/fields.py +0 -562
  342. codex/_vendor/haystack/forms.py +0 -135
  343. codex/_vendor/haystack/generic_views.py +0 -141
  344. codex/_vendor/haystack/indexes.py +0 -548
  345. codex/_vendor/haystack/inputs.py +0 -169
  346. codex/_vendor/haystack/management/__init__.py +0 -0
  347. codex/_vendor/haystack/management/commands/__init__.py +0 -0
  348. codex/_vendor/haystack/management/commands/build_solr_schema.py +0 -187
  349. codex/_vendor/haystack/management/commands/clear_index.py +0 -67
  350. codex/_vendor/haystack/management/commands/haystack_info.py +0 -22
  351. codex/_vendor/haystack/management/commands/rebuild_index.py +0 -65
  352. codex/_vendor/haystack/management/commands/update_index.py +0 -438
  353. codex/_vendor/haystack/manager.py +0 -105
  354. codex/_vendor/haystack/models.py +0 -257
  355. codex/_vendor/haystack/panels.py +0 -89
  356. codex/_vendor/haystack/query.py +0 -771
  357. codex/_vendor/haystack/routers.py +0 -14
  358. codex/_vendor/haystack/signals.py +0 -88
  359. codex/_vendor/haystack/templates/panels/haystack.html +0 -33
  360. codex/_vendor/haystack/templates/search_configuration/schema.xml +0 -1056
  361. codex/_vendor/haystack/templates/search_configuration/solrconfig.xml +0 -1446
  362. codex/_vendor/haystack/templatetags/__init__.py +0 -0
  363. codex/_vendor/haystack/templatetags/highlight.py +0 -131
  364. codex/_vendor/haystack/templatetags/more_like_this.py +0 -119
  365. codex/_vendor/haystack/urls.py +0 -5
  366. codex/_vendor/haystack/utils/__init__.py +0 -84
  367. codex/_vendor/haystack/utils/app_loading.py +0 -34
  368. codex/_vendor/haystack/utils/geo.py +0 -71
  369. codex/_vendor/haystack/utils/highlighting.py +0 -165
  370. codex/_vendor/haystack/utils/loading.py +0 -374
  371. codex/_vendor/haystack/utils/log.py +0 -21
  372. codex/_vendor/haystack/version.py +0 -16
  373. codex/_vendor/haystack/views.py +0 -253
  374. codex/integrity.py +0 -492
  375. codex/librarian/search/merge.py +0 -86
  376. codex/librarian/search/version.py +0 -63
  377. codex/search/__init__.py +0 -1
  378. codex/search/backend.py +0 -524
  379. codex/search/backend_search.py +0 -229
  380. codex/search/engine.py +0 -33
  381. codex/search/indexes.py +0 -79
  382. codex/search/query.py +0 -67
  383. codex/search/writing.py +0 -180
  384. codex/static_root/assets/VCheckbox-Cko1sQK-.170726b3b8a1.js.br +0 -0
  385. codex/static_root/assets/VCheckbox-Cko1sQK-.170726b3b8a1.js.gz +0 -0
  386. codex/static_root/assets/VCheckbox-Cko1sQK-.js.br +0 -0
  387. codex/static_root/assets/VCheckbox-Cko1sQK-.js.gz +0 -0
  388. codex/static_root/assets/VCheckboxBtn-CO3-aqQL.c9b8062fd66f.js.br +0 -0
  389. codex/static_root/assets/VCheckboxBtn-CO3-aqQL.c9b8062fd66f.js.gz +0 -0
  390. codex/static_root/assets/VCheckboxBtn-CO3-aqQL.js.br +0 -0
  391. codex/static_root/assets/VCheckboxBtn-CO3-aqQL.js.gz +0 -0
  392. codex/static_root/assets/VCombobox-Bjp6lffE.caf59fba486e.js.br +0 -0
  393. codex/static_root/assets/VCombobox-Bjp6lffE.caf59fba486e.js.gz +0 -0
  394. codex/static_root/assets/VCombobox-Bjp6lffE.js.br +0 -0
  395. codex/static_root/assets/VCombobox-Bjp6lffE.js.gz +0 -0
  396. codex/static_root/assets/VDialog-BkpVGB70.6eea3ca762a5.js.br +0 -0
  397. codex/static_root/assets/VDialog-BkpVGB70.6eea3ca762a5.js.gz +0 -0
  398. codex/static_root/assets/VDialog-BkpVGB70.js.br +0 -0
  399. codex/static_root/assets/VDialog-BkpVGB70.js.gz +0 -0
  400. codex/static_root/assets/VExpansionPanels-Ci2-j8XX.9c55db4ef49e.js.br +0 -0
  401. codex/static_root/assets/VExpansionPanels-Ci2-j8XX.9c55db4ef49e.js.gz +0 -0
  402. codex/static_root/assets/VExpansionPanels-Ci2-j8XX.js.br +0 -0
  403. codex/static_root/assets/VExpansionPanels-Ci2-j8XX.js.gz +0 -0
  404. codex/static_root/assets/VRadioGroup-D3Py5BfQ.a4f25edb86d3.js.br +0 -0
  405. codex/static_root/assets/VRadioGroup-D3Py5BfQ.a4f25edb86d3.js.gz +0 -0
  406. codex/static_root/assets/VRadioGroup-D3Py5BfQ.js.br +0 -0
  407. codex/static_root/assets/VRadioGroup-D3Py5BfQ.js.gz +0 -0
  408. codex/static_root/assets/VSelect-DtvZsYZz.e98745d858eb.js.br +0 -0
  409. codex/static_root/assets/VSelect-DtvZsYZz.e98745d858eb.js.gz +0 -0
  410. codex/static_root/assets/VSelect-DtvZsYZz.js.br +0 -0
  411. codex/static_root/assets/VSelect-DtvZsYZz.js.gz +0 -0
  412. codex/static_root/assets/VSelectionControl-D6kmykQW.1e1fda62ceba.js.br +0 -0
  413. codex/static_root/assets/VSelectionControl-D6kmykQW.1e1fda62ceba.js.gz +0 -0
  414. codex/static_root/assets/VSelectionControl-D6kmykQW.js.br +0 -0
  415. codex/static_root/assets/VSelectionControl-D6kmykQW.js.gz +0 -0
  416. codex/static_root/assets/VSlideGroup-UGZWxpF5.360bdefcd215.js.br +0 -0
  417. codex/static_root/assets/VSlideGroup-UGZWxpF5.360bdefcd215.js.gz +0 -0
  418. codex/static_root/assets/VSlideGroup-UGZWxpF5.js.br +0 -0
  419. codex/static_root/assets/VSlideGroup-UGZWxpF5.js.gz +0 -0
  420. codex/static_root/assets/VTable-DXH_yQ0o.1149f56ad566.js.br +0 -0
  421. codex/static_root/assets/VTable-DXH_yQ0o.1149f56ad566.js.gz +0 -0
  422. codex/static_root/assets/VTable-DXH_yQ0o.js.br +0 -0
  423. codex/static_root/assets/VTable-DXH_yQ0o.js.gz +0 -0
  424. codex/static_root/assets/VTextField-Blqy56_L.26d8761e0155.js.br +0 -0
  425. codex/static_root/assets/VTextField-Blqy56_L.26d8761e0155.js.gz +0 -0
  426. codex/static_root/assets/VTextField-Blqy56_L.js.br +0 -0
  427. codex/static_root/assets/VTextField-Blqy56_L.js.gz +0 -0
  428. codex/static_root/assets/VWindowItem-C8_ovV7e.afbc08414765.js.br +0 -0
  429. codex/static_root/assets/VWindowItem-C8_ovV7e.afbc08414765.js.gz +0 -0
  430. codex/static_root/assets/VWindowItem-C8_ovV7e.js.br +0 -0
  431. codex/static_root/assets/VWindowItem-C8_ovV7e.js.gz +0 -0
  432. codex/static_root/assets/admin-DTRn8bBs.d031ea42d8d0.js.br +0 -0
  433. codex/static_root/assets/admin-DTRn8bBs.d031ea42d8d0.js.gz +0 -0
  434. codex/static_root/assets/admin-DTRn8bBs.js.br +0 -0
  435. codex/static_root/assets/admin-DTRn8bBs.js.gz +0 -0
  436. codex/static_root/assets/admin-drawer-panel-BaXFOcru.b1a44b05f482.js.br +0 -0
  437. codex/static_root/assets/admin-drawer-panel-BaXFOcru.b1a44b05f482.js.gz +0 -0
  438. codex/static_root/assets/admin-drawer-panel-BaXFOcru.js.br +0 -0
  439. codex/static_root/assets/admin-drawer-panel-BaXFOcru.js.gz +0 -0
  440. codex/static_root/assets/browser-BBpUyGmz.c1cb9e2d463b.js +0 -1
  441. codex/static_root/assets/browser-BBpUyGmz.c1cb9e2d463b.js.br +0 -0
  442. codex/static_root/assets/browser-BBpUyGmz.c1cb9e2d463b.js.gz +0 -0
  443. codex/static_root/assets/browser-BBpUyGmz.js +0 -1
  444. codex/static_root/assets/browser-BBpUyGmz.js.br +0 -0
  445. codex/static_root/assets/browser-BBpUyGmz.js.gz +0 -0
  446. codex/static_root/assets/browser-Binc3n9H.313722d27ca3.css +0 -1
  447. codex/static_root/assets/browser-Binc3n9H.313722d27ca3.css.br +0 -0
  448. codex/static_root/assets/browser-Binc3n9H.313722d27ca3.css.gz +0 -0
  449. codex/static_root/assets/browser-Binc3n9H.css +0 -1
  450. codex/static_root/assets/browser-Binc3n9H.css.br +0 -0
  451. codex/static_root/assets/browser-Binc3n9H.css.gz +0 -0
  452. codex/static_root/assets/change-password-dialog-Cebek1-c.aff2975e31f8.css +0 -1
  453. codex/static_root/assets/change-password-dialog-Cebek1-c.aff2975e31f8.css.br +0 -0
  454. codex/static_root/assets/change-password-dialog-Cebek1-c.aff2975e31f8.css.gz +0 -0
  455. codex/static_root/assets/change-password-dialog-Cebek1-c.css +0 -1
  456. codex/static_root/assets/change-password-dialog-Cebek1-c.css.br +0 -0
  457. codex/static_root/assets/change-password-dialog-Cebek1-c.css.gz +0 -0
  458. codex/static_root/assets/change-password-dialog-DlHoLhDF.76ab4a29bb9b.js +0 -1
  459. codex/static_root/assets/change-password-dialog-DlHoLhDF.76ab4a29bb9b.js.br +0 -0
  460. codex/static_root/assets/change-password-dialog-DlHoLhDF.76ab4a29bb9b.js.gz +0 -0
  461. codex/static_root/assets/change-password-dialog-DlHoLhDF.js +0 -1
  462. codex/static_root/assets/change-password-dialog-DlHoLhDF.js.br +0 -0
  463. codex/static_root/assets/change-password-dialog-DlHoLhDF.js.gz +0 -0
  464. codex/static_root/assets/confirm-dialog-D3_s2DQy.9dde66036c72.js.br +0 -0
  465. codex/static_root/assets/confirm-dialog-D3_s2DQy.9dde66036c72.js.gz +0 -0
  466. codex/static_root/assets/confirm-dialog-D3_s2DQy.js.br +0 -0
  467. codex/static_root/assets/confirm-dialog-D3_s2DQy.js.gz +0 -0
  468. codex/static_root/assets/datetime-column-BxC1Li9e.3dc314b3295d.js.br +0 -0
  469. codex/static_root/assets/datetime-column-BxC1Li9e.3dc314b3295d.js.gz +0 -0
  470. codex/static_root/assets/datetime-column-BxC1Li9e.js.br +0 -0
  471. codex/static_root/assets/datetime-column-BxC1Li9e.js.gz +0 -0
  472. codex/static_root/assets/filter-Bzk7x841.d0c3b602e62d.js.br +0 -0
  473. codex/static_root/assets/filter-Bzk7x841.d0c3b602e62d.js.gz +0 -0
  474. codex/static_root/assets/filter-Bzk7x841.js.br +0 -0
  475. codex/static_root/assets/filter-Bzk7x841.js.gz +0 -0
  476. codex/static_root/assets/flag-tab-C2bI5zq3.8f8c297600a6.js +0 -1
  477. codex/static_root/assets/flag-tab-C2bI5zq3.8f8c297600a6.js.br +0 -0
  478. codex/static_root/assets/flag-tab-C2bI5zq3.8f8c297600a6.js.gz +0 -0
  479. codex/static_root/assets/flag-tab-C2bI5zq3.js +0 -1
  480. codex/static_root/assets/flag-tab-C2bI5zq3.js.br +0 -0
  481. codex/static_root/assets/flag-tab-C2bI5zq3.js.gz +0 -0
  482. codex/static_root/assets/group-tab-5esH4lwX.a81fdd258117.js.br +0 -0
  483. codex/static_root/assets/group-tab-5esH4lwX.a81fdd258117.js.gz +0 -0
  484. codex/static_root/assets/group-tab-5esH4lwX.js.br +0 -0
  485. codex/static_root/assets/group-tab-5esH4lwX.js.gz +0 -0
  486. codex/static_root/assets/http-error-BTOBfcGY.52ced6f28420.js.br +0 -0
  487. codex/static_root/assets/http-error-BTOBfcGY.52ced6f28420.js.gz +0 -0
  488. codex/static_root/assets/http-error-BTOBfcGY.js.br +0 -0
  489. codex/static_root/assets/http-error-BTOBfcGY.js.gz +0 -0
  490. codex/static_root/assets/library-tab-DiPEdOF7.ece2d642a9dc.js.br +0 -0
  491. codex/static_root/assets/library-tab-DiPEdOF7.ece2d642a9dc.js.gz +0 -0
  492. codex/static_root/assets/library-tab-DiPEdOF7.js.br +0 -0
  493. codex/static_root/assets/library-tab-DiPEdOF7.js.gz +0 -0
  494. codex/static_root/assets/main-BPIPjzsc.66def8991e38.js +0 -6
  495. codex/static_root/assets/main-BPIPjzsc.66def8991e38.js.br +0 -0
  496. codex/static_root/assets/main-BPIPjzsc.66def8991e38.js.gz +0 -0
  497. codex/static_root/assets/main-BPIPjzsc.js +0 -6
  498. codex/static_root/assets/main-BPIPjzsc.js.br +0 -0
  499. codex/static_root/assets/main-BPIPjzsc.js.gz +0 -0
  500. codex/static_root/assets/pager-full-pdf-CiyC6Al9.278b9978f36f.js +0 -1
  501. codex/static_root/assets/pager-full-pdf-CiyC6Al9.278b9978f36f.js.br +0 -0
  502. codex/static_root/assets/pager-full-pdf-CiyC6Al9.278b9978f36f.js.gz +0 -0
  503. codex/static_root/assets/pager-full-pdf-CiyC6Al9.js +0 -1
  504. codex/static_root/assets/pager-full-pdf-CiyC6Al9.js.br +0 -0
  505. codex/static_root/assets/pager-full-pdf-CiyC6Al9.js.gz +0 -0
  506. codex/static_root/assets/pagination-toolbar-C45-onwe.4722195bb60b.css.br +0 -0
  507. codex/static_root/assets/pagination-toolbar-C45-onwe.4722195bb60b.css.gz +0 -0
  508. codex/static_root/assets/pagination-toolbar-C45-onwe.css.br +0 -0
  509. codex/static_root/assets/pagination-toolbar-C45-onwe.css.gz +0 -0
  510. codex/static_root/assets/pagination-toolbar-CkIzuyx1.00c354a82e6e.js.br +0 -0
  511. codex/static_root/assets/pagination-toolbar-CkIzuyx1.00c354a82e6e.js.gz +0 -0
  512. codex/static_root/assets/pagination-toolbar-CkIzuyx1.js.br +0 -0
  513. codex/static_root/assets/pagination-toolbar-CkIzuyx1.js.gz +0 -0
  514. codex/static_root/assets/pdf-doc-BjlRPuf4.0f056fa321b6.js.br +0 -0
  515. codex/static_root/assets/pdf-doc-BjlRPuf4.0f056fa321b6.js.gz +0 -0
  516. codex/static_root/assets/pdf-doc-BjlRPuf4.js.br +0 -0
  517. codex/static_root/assets/pdf-doc-BjlRPuf4.js.gz +0 -0
  518. codex/static_root/assets/reader-_stAWL-4.5089e9144795.css +0 -1
  519. codex/static_root/assets/reader-_stAWL-4.5089e9144795.css.br +0 -0
  520. codex/static_root/assets/reader-_stAWL-4.5089e9144795.css.gz +0 -0
  521. codex/static_root/assets/reader-_stAWL-4.css +0 -1
  522. codex/static_root/assets/reader-_stAWL-4.css.br +0 -0
  523. codex/static_root/assets/reader-_stAWL-4.css.gz +0 -0
  524. codex/static_root/assets/reader-ucxnLi2K.d0fbce0f03c1.js +0 -2
  525. codex/static_root/assets/reader-ucxnLi2K.d0fbce0f03c1.js.br +0 -0
  526. codex/static_root/assets/reader-ucxnLi2K.d0fbce0f03c1.js.gz +0 -0
  527. codex/static_root/assets/reader-ucxnLi2K.js +0 -2
  528. codex/static_root/assets/reader-ucxnLi2K.js.br +0 -0
  529. codex/static_root/assets/reader-ucxnLi2K.js.gz +0 -0
  530. codex/static_root/assets/relation-chips-CUSatZET.a58031ff8141.js.br +0 -0
  531. codex/static_root/assets/relation-chips-CUSatZET.a58031ff8141.js.gz +0 -0
  532. codex/static_root/assets/relation-chips-CUSatZET.js.br +0 -0
  533. codex/static_root/assets/relation-chips-CUSatZET.js.gz +0 -0
  534. codex/static_root/assets/settings-drawer-BSHTAsJ9.1d07ce084fc9.js.br +0 -0
  535. codex/static_root/assets/settings-drawer-BSHTAsJ9.1d07ce084fc9.js.gz +0 -0
  536. codex/static_root/assets/settings-drawer-BSHTAsJ9.js.br +0 -0
  537. codex/static_root/assets/settings-drawer-BSHTAsJ9.js.gz +0 -0
  538. codex/static_root/assets/stats-tab-BXGisn5N.9b7a71e7fe28.css.br +0 -0
  539. codex/static_root/assets/stats-tab-BXGisn5N.9b7a71e7fe28.css.gz +0 -0
  540. codex/static_root/assets/stats-tab-BXGisn5N.css.br +0 -0
  541. codex/static_root/assets/stats-tab-BXGisn5N.css.gz +0 -0
  542. codex/static_root/assets/stats-tab-DKXVB2Cc.0a3de58bf5ee.js +0 -1
  543. codex/static_root/assets/stats-tab-DKXVB2Cc.0a3de58bf5ee.js.br +0 -0
  544. codex/static_root/assets/stats-tab-DKXVB2Cc.0a3de58bf5ee.js.gz +0 -0
  545. codex/static_root/assets/stats-tab-DKXVB2Cc.js +0 -1
  546. codex/static_root/assets/stats-tab-DKXVB2Cc.js.br +0 -0
  547. codex/static_root/assets/stats-tab-DKXVB2Cc.js.gz +0 -0
  548. codex/static_root/assets/task-tab-NORFAa9p.97e07e366ddd.js.br +0 -0
  549. codex/static_root/assets/task-tab-NORFAa9p.97e07e366ddd.js.gz +0 -0
  550. codex/static_root/assets/task-tab-NORFAa9p.js.br +0 -0
  551. codex/static_root/assets/task-tab-NORFAa9p.js.gz +0 -0
  552. codex/static_root/assets/unauthorized-RHaQZRfr.a234e9403f60.js +0 -1
  553. codex/static_root/assets/unauthorized-RHaQZRfr.a234e9403f60.js.br +0 -0
  554. codex/static_root/assets/unauthorized-RHaQZRfr.a234e9403f60.js.gz +0 -0
  555. codex/static_root/assets/unauthorized-RHaQZRfr.js +0 -1
  556. codex/static_root/assets/unauthorized-RHaQZRfr.js.br +0 -0
  557. codex/static_root/assets/unauthorized-RHaQZRfr.js.gz +0 -0
  558. codex/static_root/assets/unauthorized-muDsv-rC.2166ec8b3a32.css.br +0 -0
  559. codex/static_root/assets/unauthorized-muDsv-rC.2166ec8b3a32.css.gz +0 -0
  560. codex/static_root/assets/unauthorized-muDsv-rC.css.br +0 -0
  561. codex/static_root/assets/unauthorized-muDsv-rC.css.gz +0 -0
  562. codex/static_root/assets/user-tab-CHbyN1EW.e7206db08680.js.br +0 -0
  563. codex/static_root/assets/user-tab-CHbyN1EW.e7206db08680.js.gz +0 -0
  564. codex/static_root/assets/user-tab-CHbyN1EW.js.br +0 -0
  565. codex/static_root/assets/user-tab-CHbyN1EW.js.gz +0 -0
  566. codex/static_root/js/choices-admin.1a20a5648f20.json +0 -1
  567. codex/static_root/js/choices-admin.1a20a5648f20.json.br +0 -0
  568. codex/static_root/js/choices-admin.1a20a5648f20.json.gz +0 -0
  569. codex/static_root/manifest.0fe31a6cb99f.json +0 -635
  570. codex/static_root/manifest.0fe31a6cb99f.json.br +0 -0
  571. codex/static_root/manifest.0fe31a6cb99f.json.gz +0 -0
  572. codex/templates/search/indexes/codex/comic_text.txt +0 -47
  573. codex/views/browser/filters/search.py +0 -196
  574. {codex-1.6.19.dist-info → codex-1.7.0a0.dist-info}/LICENSE +0 -0
  575. {codex-1.6.19.dist-info → codex-1.7.0a0.dist-info}/WHEEL +0 -0
  576. {codex-1.6.19.dist-info → codex-1.7.0a0.dist-info}/entry_points.txt +0 -0
@@ -1,771 +0,0 @@
1
- import operator
2
- import warnings
3
- from functools import reduce
4
-
5
- from ..haystack import connection_router, connections
6
- from ..haystack.backends import SQ
7
- from ..haystack.constants import DEFAULT_OPERATOR, ITERATOR_LOAD_PER_QUERY
8
- from ..haystack.exceptions import NotHandled
9
- from ..haystack.inputs import AutoQuery, Raw
10
- from ..haystack.utils import log as logging
11
-
12
-
13
- class SearchQuerySet:
14
- """
15
- Provides a way to specify search parameters and lazily load results.
16
-
17
- Supports chaining (a la QuerySet) to narrow the search.
18
- """
19
-
20
- def __init__(self, using=None, query=None):
21
- # ``_using`` should only ever be a value other than ``None`` if it's
22
- # been forced with the ``.using`` method.
23
- self._using = using
24
- self.query = None
25
- self._determine_backend()
26
-
27
- # If ``query`` is present, it should override even what the routers
28
- # think.
29
- if query is not None:
30
- self.query = query
31
-
32
- self._result_cache = []
33
- self._result_count = None
34
- self._cache_full = False
35
- self._load_all = False
36
- self._ignored_result_count = 0
37
- self.log = logging.getLogger("haystack")
38
-
39
- def _determine_backend(self):
40
- # A backend has been manually selected. Use it instead.
41
- if self._using is not None:
42
- self.query = connections[self._using].get_query()
43
- return
44
-
45
- # No backend, so rely on the routers to figure out what's right.
46
- hints = {}
47
-
48
- if self.query:
49
- hints["models"] = self.query.models
50
-
51
- backend_alias = connection_router.for_read(**hints)
52
-
53
- # The ``SearchQuery`` might swap itself out for a different variant
54
- # here.
55
- if self.query:
56
- self.query = self.query.using(backend_alias)
57
- else:
58
- self.query = connections[backend_alias].get_query()
59
-
60
- def __getstate__(self):
61
- """
62
- For pickling.
63
- """
64
- len(self)
65
- obj_dict = self.__dict__.copy()
66
- obj_dict["_iter"] = None
67
- obj_dict["log"] = None
68
- return obj_dict
69
-
70
- def __setstate__(self, data_dict):
71
- """
72
- For unpickling.
73
- """
74
- self.__dict__ = data_dict
75
- self.log = logging.getLogger("haystack")
76
-
77
- def __repr__(self):
78
- return "<SearchQuerySet: query=%r, using=%r>" % (self.query, self._using)
79
-
80
- def __len__(self):
81
- if self._result_count is None:
82
- self._result_count = self.query.get_count()
83
-
84
- # Some backends give weird, false-y values here. Convert to zero.
85
- if not self._result_count:
86
- self._result_count = 0
87
-
88
- # This needs to return the actual number of hits, not what's in the cache.
89
- return self._result_count - self._ignored_result_count
90
-
91
- def __iter__(self):
92
- if self._cache_is_full():
93
- # We've got a fully populated cache. Let Python do the hard work.
94
- return iter(self._result_cache)
95
-
96
- return self._manual_iter()
97
-
98
- def __and__(self, other):
99
- if isinstance(other, EmptySearchQuerySet):
100
- return other._clone()
101
- combined = self._clone()
102
- combined.query.combine(other.query, SQ.AND)
103
- return combined
104
-
105
- def __or__(self, other):
106
- combined = self._clone()
107
- if isinstance(other, EmptySearchQuerySet):
108
- return combined
109
- combined.query.combine(other.query, SQ.OR)
110
- return combined
111
-
112
- def _cache_is_full(self):
113
- if not self.query.has_run():
114
- return False
115
-
116
- if len(self) <= 0:
117
- return True
118
-
119
- try:
120
- self._result_cache.index(None)
121
- return False
122
- except ValueError:
123
- # No ``None``s found in the results. Check the length of the cache.
124
- return len(self._result_cache) > 0
125
-
126
- def _manual_iter(self):
127
- # If we're here, our cache isn't fully populated.
128
- # For efficiency, fill the cache as we go if we run out of results.
129
- # Also, this can't be part of the __iter__ method due to Python's rules
130
- # about generator functions.
131
- current_position = 0
132
- current_cache_max = 0
133
-
134
- while True:
135
- if len(self._result_cache) > 0:
136
- try:
137
- current_cache_max = self._result_cache.index(None)
138
- except ValueError:
139
- current_cache_max = len(self._result_cache)
140
-
141
- while current_position < current_cache_max:
142
- yield self._result_cache[current_position]
143
- current_position += 1
144
-
145
- if self._cache_is_full():
146
- return
147
-
148
- # We've run out of results and haven't hit our limit.
149
- # Fill more of the cache.
150
- if not self._fill_cache(
151
- current_position, current_position + ITERATOR_LOAD_PER_QUERY
152
- ):
153
- return
154
-
155
- def post_process_results(self, results):
156
- to_cache = []
157
-
158
- # Check if we wish to load all objects.
159
- if self._load_all:
160
- models_pks = {}
161
- loaded_objects = {}
162
-
163
- # Remember the search position for each result so we don't have to resort later.
164
- for result in results:
165
- models_pks.setdefault(result.model, []).append(result.pk)
166
-
167
- # Load the objects for each model in turn.
168
- for model in models_pks:
169
- loaded_objects[model] = self._load_model_objects(
170
- model, models_pks[model]
171
- )
172
-
173
- for result in results:
174
- if self._load_all:
175
-
176
- model_objects = loaded_objects.get(result.model, {})
177
- # Try to coerce a primary key object that matches the models pk
178
- # We have to deal with semi-arbitrary keys being cast from strings (UUID, int, etc)
179
- if model_objects:
180
- result_klass = type(next(iter(model_objects)))
181
- result.pk = result_klass(result.pk)
182
-
183
- try:
184
- result._object = model_objects[result.pk]
185
- except KeyError:
186
- # The object was either deleted since we indexed or should
187
- # be ignored for other reasons such as an overriden 'load_all_queryset';
188
- # fail silently.
189
- self._ignored_result_count += 1
190
-
191
- # avoid an unfilled None at the end of the result cache
192
- self._result_cache.pop()
193
- continue
194
- else:
195
- # No objects were returned -- possible due to SQS nesting such as
196
- # XYZ.objects.filter(id__gt=10) where the amount ignored are
197
- # exactly equal to the ITERATOR_LOAD_PER_QUERY
198
- del self._result_cache[: len(results)]
199
- self._ignored_result_count += len(results)
200
- break
201
-
202
- to_cache.append(result)
203
-
204
- return to_cache
205
-
206
- def _load_model_objects(self, model, pks):
207
- try:
208
- ui = connections[self.query._using].get_unified_index()
209
- index = ui.get_index(model)
210
- objects = index.read_queryset(using=self.query._using)
211
- return objects.in_bulk(pks)
212
- except NotHandled:
213
- self.log.warning("Model '%s' not handled by the routers.", model)
214
- # Revert to old behaviour
215
- return model._default_manager.in_bulk(pks)
216
-
217
- def _fill_cache(self, start, end, **kwargs):
218
- # Tell the query where to start from and how many we'd like.
219
- self.query._reset()
220
-
221
- if start is None:
222
- start = 0
223
-
224
- query_start = start
225
- query_start += self._ignored_result_count
226
- query_end = end
227
- if query_end is not None:
228
- query_end += self._ignored_result_count
229
-
230
- self.query.set_limits(query_start, query_end)
231
- results = self.query.get_results(**kwargs)
232
-
233
- if results is None or len(results) == 0:
234
- # trim missing stuff from the result cache
235
- self._result_cache = self._result_cache[:start]
236
- return False
237
-
238
- # Setup the full cache now that we know how many results there are.
239
- # We need the ``None``s as placeholders to know what parts of the
240
- # cache we have/haven't filled.
241
- # Using ``None`` like this takes up very little memory. In testing,
242
- # an array of 100,000 ``None``s consumed less than .5 Mb, which ought
243
- # to be an acceptable loss for consistent and more efficient caching.
244
- if len(self._result_cache) == 0:
245
- self._result_cache = [None] * self.query.get_count()
246
-
247
- fill_start, fill_end = start, end
248
- if fill_end is None:
249
- fill_end = self.query.get_count()
250
- cache_start = fill_start
251
-
252
- while True:
253
- to_cache = self.post_process_results(results)
254
-
255
- # Assign by slice.
256
- self._result_cache[cache_start : cache_start + len(to_cache)] = to_cache
257
-
258
- if None in self._result_cache[start:end]:
259
- fill_start = fill_end
260
- fill_end += ITERATOR_LOAD_PER_QUERY
261
- cache_start += len(to_cache)
262
-
263
- # Tell the query where to start from and how many we'd like.
264
- self.query._reset()
265
- self.query.set_limits(fill_start, fill_end)
266
- results = self.query.get_results()
267
-
268
- if results is None or len(results) == 0:
269
- # No more results. Trim missing stuff from the result cache
270
- self._result_cache = self._result_cache[:cache_start]
271
- break
272
- else:
273
- break
274
-
275
- return True
276
-
277
- def __getitem__(self, k):
278
- """
279
- Retrieves an item or slice from the set of results.
280
- """
281
- if not isinstance(k, (slice, int)):
282
- raise TypeError
283
- assert (not isinstance(k, slice) and (k >= 0)) or (
284
- isinstance(k, slice)
285
- and (k.start is None or k.start >= 0)
286
- and (k.stop is None or k.stop >= 0)
287
- ), "Negative indexing is not supported."
288
-
289
- # Remember if it's a slice or not. We're going to treat everything as
290
- # a slice to simply the logic and will `.pop()` at the end as needed.
291
- if isinstance(k, slice):
292
- is_slice = True
293
- start = k.start
294
-
295
- if k.stop is not None:
296
- bound = int(k.stop)
297
- else:
298
- bound = None
299
- else:
300
- is_slice = False
301
- start = k
302
- bound = k + 1
303
-
304
- # We need check to see if we need to populate more of the cache.
305
- if len(self._result_cache) <= 0 or (
306
- None in self._result_cache[start:bound] and not self._cache_is_full()
307
- ):
308
- try:
309
- self._fill_cache(start, bound)
310
- except StopIteration:
311
- # There's nothing left, even though the bound is higher.
312
- pass
313
-
314
- # Cache should be full enough for our needs.
315
- if is_slice:
316
- return self._result_cache[start:bound]
317
- else:
318
- return self._result_cache[start]
319
-
320
- # Methods that return a SearchQuerySet.
321
- def all(self): # noqa A003
322
- """Returns all results for the query."""
323
- return self._clone()
324
-
325
- def none(self):
326
- """Returns an empty result list for the query."""
327
- return self._clone(klass=EmptySearchQuerySet)
328
-
329
- def filter(self, *args, **kwargs): # noqa A003
330
- """Narrows the search based on certain attributes and the default operator."""
331
- if DEFAULT_OPERATOR == "OR":
332
- return self.filter_or(*args, **kwargs)
333
- else:
334
- return self.filter_and(*args, **kwargs)
335
-
336
- def exclude(self, *args, **kwargs):
337
- """Narrows the search by ensuring certain attributes are not included."""
338
- clone = self._clone()
339
- clone.query.add_filter(~SQ(*args, **kwargs))
340
- return clone
341
-
342
- def filter_and(self, *args, **kwargs):
343
- """Narrows the search by looking for (and including) certain attributes."""
344
- clone = self._clone()
345
- clone.query.add_filter(SQ(*args, **kwargs))
346
- return clone
347
-
348
- def filter_or(self, *args, **kwargs):
349
- """Narrows the search by ensuring certain attributes are not included."""
350
- clone = self._clone()
351
- clone.query.add_filter(SQ(*args, **kwargs), use_or=True)
352
- return clone
353
-
354
- def order_by(self, *args):
355
- """Alters the order in which the results should appear."""
356
- clone = self._clone()
357
-
358
- for field in args:
359
- clone.query.add_order_by(field)
360
-
361
- return clone
362
-
363
- def highlight(self, **kwargs):
364
- """Adds highlighting to the results."""
365
- clone = self._clone()
366
- clone.query.add_highlight(**kwargs)
367
- return clone
368
-
369
- def models(self, *models):
370
- """Accepts an arbitrary number of Model classes to include in the search."""
371
- clone = self._clone()
372
-
373
- for model in models:
374
- if (
375
- model
376
- not in connections[self.query._using]
377
- .get_unified_index()
378
- .get_indexed_models()
379
- ):
380
- warnings.warn("The model %r is not registered for search." % (model,))
381
-
382
- clone.query.add_model(model)
383
-
384
- return clone
385
-
386
- def result_class(self, klass):
387
- """
388
- Allows specifying a different class to use for results.
389
-
390
- Overrides any previous usages. If ``None`` is provided, Haystack will
391
- revert back to the default ``SearchResult`` object.
392
- """
393
- clone = self._clone()
394
- clone.query.set_result_class(klass)
395
- return clone
396
-
397
- def boost(self, term, boost):
398
- """Boosts a certain aspect of the query."""
399
- clone = self._clone()
400
- clone.query.add_boost(term, boost)
401
- return clone
402
-
403
- def facet(self, field, **options):
404
- """Adds faceting to a query for the provided field."""
405
- clone = self._clone()
406
- clone.query.add_field_facet(field, **options)
407
- return clone
408
-
409
- def within(self, field, point_1, point_2):
410
- """Spatial: Adds a bounding box search to the query."""
411
- clone = self._clone()
412
- clone.query.add_within(field, point_1, point_2)
413
- return clone
414
-
415
- def dwithin(self, field, point, distance):
416
- """Spatial: Adds a distance-based search to the query."""
417
- clone = self._clone()
418
- clone.query.add_dwithin(field, point, distance)
419
- return clone
420
-
421
- def stats(self, field):
422
- """Adds stats to a query for the provided field."""
423
- return self.stats_facet(field, facet_fields=None)
424
-
425
- def stats_facet(self, field, facet_fields=None):
426
- """Adds stats facet for the given field and facet_fields represents
427
- the faceted fields."""
428
- clone = self._clone()
429
- stats_facets = []
430
- try:
431
- stats_facets.append(sum(facet_fields, []))
432
- except TypeError:
433
- if facet_fields:
434
- stats_facets.append(facet_fields)
435
- clone.query.add_stats_query(field, stats_facets)
436
- return clone
437
-
438
- def distance(self, field, point):
439
- """
440
- Spatial: Denotes results must have distance measurements from the
441
- provided point.
442
- """
443
- clone = self._clone()
444
- clone.query.add_distance(field, point)
445
- return clone
446
-
447
- def date_facet(self, field, start_date, end_date, gap_by, gap_amount=1):
448
- """Adds faceting to a query for the provided field by date."""
449
- clone = self._clone()
450
- clone.query.add_date_facet(
451
- field, start_date, end_date, gap_by, gap_amount=gap_amount
452
- )
453
- return clone
454
-
455
- def query_facet(self, field, query):
456
- """Adds faceting to a query for the provided field with a custom query."""
457
- clone = self._clone()
458
- clone.query.add_query_facet(field, query)
459
- return clone
460
-
461
- def narrow(self, query):
462
- """Pushes existing facet choices into the search."""
463
-
464
- if isinstance(query, SQ):
465
- # produce query string using empty query of the same class
466
- empty_query = self.query._clone()
467
- empty_query._reset()
468
- query = query.as_query_string(empty_query.build_query_fragment)
469
-
470
- clone = self._clone()
471
- clone.query.add_narrow_query(query)
472
- return clone
473
-
474
- def raw_search(self, query_string, **kwargs):
475
- """Passes a raw query directly to the backend."""
476
- return self.filter(content=Raw(query_string, **kwargs))
477
-
478
- def load_all(self):
479
- """Efficiently populates the objects in the search results."""
480
- clone = self._clone()
481
- clone._load_all = True
482
- return clone
483
-
484
- def auto_query(self, query_string, fieldname="content"):
485
- """
486
- Performs a best guess constructing the search query.
487
-
488
- This method is somewhat naive but works well enough for the simple,
489
- common cases.
490
- """
491
- kwargs = {fieldname: AutoQuery(query_string)}
492
- return self.filter(**kwargs)
493
-
494
- def autocomplete(self, **kwargs):
495
- """
496
- A shortcut method to perform an autocomplete search.
497
-
498
- Must be run against fields that are either ``NgramField`` or
499
- ``EdgeNgramField``.
500
- """
501
- clone = self._clone()
502
- query_bits = []
503
-
504
- for field_name, query in kwargs.items():
505
- for word in query.split(" "):
506
- bit = clone.query.clean(word.strip())
507
- if bit:
508
- kwargs = {field_name: bit}
509
- query_bits.append(SQ(**kwargs))
510
-
511
- return clone.filter(reduce(operator.__and__, query_bits))
512
-
513
- def using(self, connection_name):
514
- """
515
- Allows switching which connection the ``SearchQuerySet`` uses to
516
- search in.
517
- """
518
- clone = self._clone()
519
- clone.query = self.query.using(connection_name)
520
- clone._using = connection_name
521
- return clone
522
-
523
- # Methods that do not return a SearchQuerySet.
524
-
525
- def count(self):
526
- """Returns the total number of matching results."""
527
- return len(self)
528
-
529
- def best_match(self):
530
- """Returns the best/top search result that matches the query."""
531
- return self[0]
532
-
533
- def latest(self, date_field):
534
- """Returns the most recent search result that matches the query."""
535
- clone = self._clone()
536
- clone.query.clear_order_by()
537
- clone.query.add_order_by("-%s" % date_field)
538
- return clone.best_match()
539
-
540
- def more_like_this(self, model_instance):
541
- """Finds similar results to the object passed in."""
542
- clone = self._clone()
543
- clone.query.more_like_this(model_instance)
544
- return clone
545
-
546
- def facet_counts(self):
547
- """
548
- Returns the facet counts found by the query.
549
-
550
- This will cause the query to execute and should generally be used when
551
- presenting the data.
552
- """
553
- if self.query.has_run():
554
- return self.query.get_facet_counts()
555
- else:
556
- clone = self._clone()
557
- return clone.query.get_facet_counts()
558
-
559
- def stats_results(self):
560
- """
561
- Returns the stats results found by the query.
562
- """
563
- if self.query.has_run():
564
- return self.query.get_stats()
565
- else:
566
- clone = self._clone()
567
- return clone.query.get_stats()
568
-
569
- def set_spelling_query(self, spelling_query):
570
- """Set the exact text to be used to generate spelling suggestions
571
-
572
- When making complicated queries, such as the alt parser mechanism
573
- used by Solr dismax/edismax, this provides a convenient way to set
574
- the a simple text string which will be used to generate spelling
575
- suggestions without including unnecessary syntax.
576
- """
577
- clone = self._clone()
578
- clone.query.set_spelling_query(spelling_query)
579
- return clone
580
-
581
- def spelling_suggestion(self, preferred_query=None):
582
- """
583
- Returns the spelling suggestion found by the query.
584
-
585
- To work, you must set ``INCLUDE_SPELLING`` within your connection's
586
- settings dictionary to ``True``. Otherwise, ``None`` will be returned.
587
-
588
- This will cause the query to execute and should generally be used when
589
- presenting the data.
590
- """
591
- if self.query.has_run():
592
- return self.query.get_spelling_suggestion(preferred_query)
593
- else:
594
- clone = self._clone()
595
- return clone.query.get_spelling_suggestion(preferred_query)
596
-
597
- def values(self, *fields):
598
- """
599
- Returns a list of dictionaries, each containing the key/value pairs for
600
- the result, exactly like Django's ``ValuesQuerySet``.
601
- """
602
- qs = self._clone(klass=ValuesSearchQuerySet)
603
- qs._fields.extend(fields)
604
- return qs
605
-
606
- def values_list(self, *fields, **kwargs):
607
- """
608
- Returns a list of field values as tuples, exactly like Django's
609
- ``QuerySet.values``.
610
-
611
- Optionally accepts a ``flat=True`` kwarg, which in the case of a
612
- single field being provided, will return a flat list of that field
613
- rather than a list of tuples.
614
- """
615
- flat = kwargs.pop("flat", False)
616
-
617
- if flat and len(fields) > 1:
618
- raise TypeError(
619
- "'flat' is not valid when values_list is called with more than one field."
620
- )
621
-
622
- qs = self._clone(klass=ValuesListSearchQuerySet)
623
- qs._fields.extend(fields)
624
- qs._flat = flat
625
- return qs
626
-
627
- # Utility methods.
628
-
629
- def _clone(self, klass=None):
630
- if klass is None:
631
- klass = self.__class__
632
-
633
- query = self.query._clone()
634
- clone = klass(query=query)
635
- clone._load_all = self._load_all
636
- return clone
637
-
638
-
639
- class EmptySearchQuerySet(SearchQuerySet):
640
- """
641
- A stubbed SearchQuerySet that behaves as normal but always returns no
642
- results.
643
- """
644
-
645
- def __len__(self):
646
- return 0
647
-
648
- def _cache_is_full(self):
649
- # Pretend the cache is always full with no results.
650
- return True
651
-
652
- def _clone(self, klass=None):
653
- clone = super()._clone(klass=klass)
654
- clone._result_cache = []
655
- return clone
656
-
657
- def _fill_cache(self, start, end):
658
- return False
659
-
660
- def facet_counts(self):
661
- return {}
662
-
663
-
664
- class ValuesListSearchQuerySet(SearchQuerySet):
665
- """
666
- A ``SearchQuerySet`` which returns a list of field values as tuples, exactly
667
- like Django's ``ValuesListQuerySet``.
668
- """
669
-
670
- def __init__(self, *args, **kwargs):
671
- super().__init__(*args, **kwargs)
672
- self._flat = False
673
- self._fields = []
674
-
675
- # Removing this dependency would require refactoring much of the backend
676
- # code (_process_results, etc.) and these aren't large enough to make it
677
- # an immediate priority:
678
- self._internal_fields = ["id", "django_ct", "django_id", "score"]
679
-
680
- def _clone(self, klass=None):
681
- clone = super()._clone(klass=klass)
682
- clone._fields = self._fields
683
- clone._flat = self._flat
684
- return clone
685
-
686
- def _fill_cache(self, start, end):
687
- query_fields = set(self._internal_fields)
688
- query_fields.update(self._fields)
689
- kwargs = {"fields": query_fields}
690
- return super()._fill_cache(start, end, **kwargs)
691
-
692
- def post_process_results(self, results):
693
- to_cache = []
694
-
695
- if self._flat:
696
- accum = to_cache.extend
697
- else:
698
- accum = to_cache.append
699
-
700
- for result in results:
701
- accum([getattr(result, i, None) for i in self._fields])
702
-
703
- return to_cache
704
-
705
-
706
- class ValuesSearchQuerySet(ValuesListSearchQuerySet):
707
- """
708
- A ``SearchQuerySet`` which returns a list of dictionaries, each containing
709
- the key/value pairs for the result, exactly like Django's
710
- ``ValuesQuerySet``.
711
- """
712
-
713
- def _fill_cache(self, start, end):
714
- query_fields = set(self._internal_fields)
715
- query_fields.update(self._fields)
716
- kwargs = {"fields": query_fields}
717
- return super(ValuesListSearchQuerySet, self)._fill_cache(start, end, **kwargs)
718
-
719
- def post_process_results(self, results):
720
- to_cache = []
721
-
722
- for result in results:
723
- to_cache.append({i: getattr(result, i, None) for i in self._fields})
724
-
725
- return to_cache
726
-
727
-
728
- class RelatedSearchQuerySet(SearchQuerySet):
729
- """
730
- A variant of the SearchQuerySet that can handle `load_all_queryset`s.
731
- """
732
-
733
- def __init__(self, *args, **kwargs):
734
- super().__init__(*args, **kwargs)
735
- self._load_all_querysets = {}
736
- self._result_cache = []
737
-
738
- def _load_model_objects(self, model, pks):
739
- if model in self._load_all_querysets:
740
- # Use the overriding queryset.
741
- return self._load_all_querysets[model].in_bulk(pks)
742
- else:
743
- # Check the SearchIndex for the model for an override.
744
-
745
- try:
746
- ui = connections[self.query._using].get_unified_index()
747
- index = ui.get_index(model)
748
- qs = index.load_all_queryset()
749
- return qs.in_bulk(pks)
750
- except NotHandled:
751
- # The model returned doesn't seem to be handled by the
752
- # routers. We should silently fail and populate
753
- # nothing for those objects.
754
- return {}
755
-
756
- def load_all_queryset(self, model, queryset):
757
- """
758
- Allows for specifying a custom ``QuerySet`` that changes how ``load_all``
759
- will fetch records for the provided model.
760
-
761
- This is useful for post-processing the results from the query, enabling
762
- things like adding ``select_related`` or filtering certain data.
763
- """
764
- clone = self._clone()
765
- clone._load_all_querysets[model] = queryset
766
- return clone
767
-
768
- def _clone(self, klass=None):
769
- clone = super()._clone(klass=klass)
770
- clone._load_all_querysets = self._load_all_querysets
771
- return clone