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.
- codex/db.py +119 -0
- codex/librarian/covers/purge.py +1 -1
- codex/librarian/importer/const.py +7 -1
- codex/librarian/importer/create_fks.py +5 -2
- codex/librarian/importer/importerd.py +17 -12
- codex/librarian/importer/moved.py +44 -13
- codex/librarian/importer/tasks.py +2 -0
- codex/librarian/janitor/cleanup.py +21 -8
- codex/librarian/janitor/integrity.py +369 -0
- codex/librarian/janitor/janitor.py +50 -15
- codex/librarian/janitor/latest_version.py +2 -1
- codex/librarian/janitor/status.py +5 -0
- codex/librarian/janitor/tasks.py +37 -0
- codex/librarian/janitor/update.py +1 -1
- codex/librarian/librariand.py +32 -24
- codex/librarian/search/optimize.py +43 -0
- codex/librarian/search/remove.py +18 -46
- codex/librarian/search/searchd.py +14 -17
- codex/librarian/search/status.py +2 -1
- codex/librarian/search/tasks.py +4 -9
- codex/librarian/search/update.py +223 -301
- codex/librarian/watchdog/observers.py +2 -1
- codex/migrations/0029_comicfts.py +58 -0
- codex/migrations/0030_nocase_collation_day_month_indexes_status_types.py +198 -0
- codex/models/admin.py +15 -6
- codex/models/base.py +9 -0
- codex/models/bookmark.py +3 -3
- codex/models/comic.py +68 -16
- codex/models/functions.py +59 -2
- codex/models/groups.py +6 -1
- codex/models/library.py +1 -3
- codex/models/paths.py +9 -3
- codex/serializers/browser/page.py +2 -0
- codex/settings/settings.py +16 -17
- codex/signals/django_signals.py +4 -10
- codex/startup.py +1 -35
- codex/static_root/assets/{VCheckbox-Cko1sQK-.170726b3b8a1.js → VCheckbox-CWiqcZ7a.3feebd47daab.js} +1 -1
- codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js.br +0 -0
- codex/static_root/assets/VCheckbox-CWiqcZ7a.3feebd47daab.js.gz +0 -0
- codex/static_root/assets/{VCheckbox-Cko1sQK-.js → VCheckbox-CWiqcZ7a.js} +1 -1
- codex/static_root/assets/VCheckbox-CWiqcZ7a.js.br +0 -0
- codex/static_root/assets/VCheckbox-CWiqcZ7a.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-CO3-aqQL.c9b8062fd66f.js → VCheckboxBtn-Dk3iB62X.bc66d5351baa.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-Dk3iB62X.bc66d5351baa.js.gz +0 -0
- codex/static_root/assets/{VCheckboxBtn-CO3-aqQL.js → VCheckboxBtn-Dk3iB62X.js} +1 -1
- codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-Dk3iB62X.js.gz +0 -0
- codex/static_root/assets/{VCombobox-Bjp6lffE.js → VCombobox-D1_KU27A.b1d30587a973.js} +1 -1
- codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js.br +0 -0
- codex/static_root/assets/VCombobox-D1_KU27A.b1d30587a973.js.gz +0 -0
- codex/static_root/assets/{VCombobox-Bjp6lffE.caf59fba486e.js → VCombobox-D1_KU27A.js} +1 -1
- codex/static_root/assets/VCombobox-D1_KU27A.js.br +0 -0
- codex/static_root/assets/VCombobox-D1_KU27A.js.gz +0 -0
- codex/static_root/assets/{VDialog-BkpVGB70.6eea3ca762a5.js → VDialog-GbxvFMMN.594fb3a39ced.js} +1 -1
- codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js.br +0 -0
- codex/static_root/assets/VDialog-GbxvFMMN.594fb3a39ced.js.gz +0 -0
- codex/static_root/assets/{VDialog-BkpVGB70.js → VDialog-GbxvFMMN.js} +1 -1
- codex/static_root/assets/VDialog-GbxvFMMN.js.br +0 -0
- codex/static_root/assets/VDialog-GbxvFMMN.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-Ci2-j8XX.9c55db4ef49e.js → VExpansionPanels-Cywv_bEj.a762e63858e5.js} +1 -1
- codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-Cywv_bEj.a762e63858e5.js.gz +0 -0
- codex/static_root/assets/{VExpansionPanels-Ci2-j8XX.js → VExpansionPanels-Cywv_bEj.js} +1 -1
- codex/static_root/assets/VExpansionPanels-Cywv_bEj.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-Cywv_bEj.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-D3Py5BfQ.a4f25edb86d3.js → VRadioGroup-C0etmxpZ.0eb3009a6300.js} +1 -1
- codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js.br +0 -0
- codex/static_root/assets/VRadioGroup-C0etmxpZ.0eb3009a6300.js.gz +0 -0
- codex/static_root/assets/{VRadioGroup-D3Py5BfQ.js → VRadioGroup-C0etmxpZ.js} +1 -1
- codex/static_root/assets/VRadioGroup-C0etmxpZ.js.br +0 -0
- codex/static_root/assets/VRadioGroup-C0etmxpZ.js.gz +0 -0
- codex/static_root/assets/{VSelect-DtvZsYZz.e98745d858eb.js → VSelect-txrnRiNJ.a5625760018c.js} +1 -1
- codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js.br +0 -0
- codex/static_root/assets/VSelect-txrnRiNJ.a5625760018c.js.gz +0 -0
- codex/static_root/assets/{VSelect-DtvZsYZz.js → VSelect-txrnRiNJ.js} +1 -1
- codex/static_root/assets/VSelect-txrnRiNJ.js.br +0 -0
- codex/static_root/assets/VSelect-txrnRiNJ.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-D6kmykQW.1e1fda62ceba.js → VSelectionControl-CY6RmcvW.7e8824224f6c.js} +1 -1
- codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CY6RmcvW.7e8824224f6c.js.gz +0 -0
- codex/static_root/assets/{VSelectionControl-D6kmykQW.js → VSelectionControl-CY6RmcvW.js} +1 -1
- codex/static_root/assets/VSelectionControl-CY6RmcvW.js.br +0 -0
- codex/static_root/assets/VSelectionControl-CY6RmcvW.js.gz +0 -0
- codex/static_root/assets/{VSlideGroup-UGZWxpF5.360bdefcd215.js → VSlideGroup-DtEQMwY1.6c72325635ed.js} +1 -1
- codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js.br +0 -0
- codex/static_root/assets/VSlideGroup-DtEQMwY1.6c72325635ed.js.gz +0 -0
- codex/static_root/assets/{VSlideGroup-UGZWxpF5.js → VSlideGroup-DtEQMwY1.js} +1 -1
- codex/static_root/assets/VSlideGroup-DtEQMwY1.js.br +0 -0
- codex/static_root/assets/VSlideGroup-DtEQMwY1.js.gz +0 -0
- codex/static_root/assets/{VTable-DXH_yQ0o.1149f56ad566.js → VTable-2af995xo.6c5bf36631b2.js} +1 -1
- codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js.br +0 -0
- codex/static_root/assets/VTable-2af995xo.6c5bf36631b2.js.gz +0 -0
- codex/static_root/assets/{VTable-DXH_yQ0o.js → VTable-2af995xo.js} +1 -1
- codex/static_root/assets/VTable-2af995xo.js.br +0 -0
- codex/static_root/assets/VTable-2af995xo.js.gz +0 -0
- codex/static_root/assets/{VTextField-Blqy56_L.26d8761e0155.js → VTextField-G6CMj7yO.657a130dd302.js} +1 -1
- codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js.br +0 -0
- codex/static_root/assets/VTextField-G6CMj7yO.657a130dd302.js.gz +0 -0
- codex/static_root/assets/{VTextField-Blqy56_L.js → VTextField-G6CMj7yO.js} +1 -1
- codex/static_root/assets/VTextField-G6CMj7yO.js.br +0 -0
- codex/static_root/assets/VTextField-G6CMj7yO.js.gz +0 -0
- codex/static_root/assets/{VWindowItem-C8_ovV7e.afbc08414765.js → VWindowItem-CzoGd6Ul.721e5da11ad4.js} +1 -1
- codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js.br +0 -0
- codex/static_root/assets/VWindowItem-CzoGd6Ul.721e5da11ad4.js.gz +0 -0
- codex/static_root/assets/{VWindowItem-C8_ovV7e.js → VWindowItem-CzoGd6Ul.js} +1 -1
- codex/static_root/assets/VWindowItem-CzoGd6Ul.js.br +0 -0
- codex/static_root/assets/VWindowItem-CzoGd6Ul.js.gz +0 -0
- codex/static_root/assets/{admin-DTRn8bBs.d031ea42d8d0.js → admin-CsPAIQeG.5175467148a3.js} +1 -1
- codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js.br +0 -0
- codex/static_root/assets/admin-CsPAIQeG.5175467148a3.js.gz +0 -0
- codex/static_root/assets/{admin-DTRn8bBs.js → admin-CsPAIQeG.js} +1 -1
- codex/static_root/assets/admin-CsPAIQeG.js.br +0 -0
- codex/static_root/assets/admin-CsPAIQeG.js.gz +0 -0
- codex/static_root/assets/{admin-drawer-panel-BaXFOcru.b1a44b05f482.js → admin-drawer-panel-BAT7GA64.73a064628c19.js} +11 -11
- codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BAT7GA64.73a064628c19.js.gz +0 -0
- codex/static_root/assets/{admin-drawer-panel-BaXFOcru.js → admin-drawer-panel-BAT7GA64.js} +11 -11
- codex/static_root/assets/admin-drawer-panel-BAT7GA64.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BAT7GA64.js.gz +0 -0
- codex/static_root/assets/browser-C18l93yc.923860009ef4.js +1 -0
- codex/static_root/assets/browser-C18l93yc.923860009ef4.js.br +0 -0
- codex/static_root/assets/browser-C18l93yc.923860009ef4.js.gz +0 -0
- codex/static_root/assets/browser-C18l93yc.js +1 -0
- codex/static_root/assets/browser-C18l93yc.js.br +0 -0
- codex/static_root/assets/browser-C18l93yc.js.gz +0 -0
- codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css +1 -0
- codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css.br +0 -0
- codex/static_root/assets/browser-DaAqlBYO.708ecf0904bb.css.gz +0 -0
- codex/static_root/assets/browser-DaAqlBYO.css +1 -0
- codex/static_root/assets/browser-DaAqlBYO.css.br +0 -0
- codex/static_root/assets/browser-DaAqlBYO.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js +1 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.0a4e02656a35.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.js +1 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.js.br +0 -0
- codex/static_root/assets/change-password-dialog-BazJdNs9.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css +1 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css.br +0 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.111421f51e79.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.css +1 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.css.br +0 -0
- codex/static_root/assets/change-password-dialog-Mlmvz8_4.css.gz +0 -0
- codex/static_root/assets/{confirm-dialog-D3_s2DQy.9dde66036c72.js → confirm-dialog-CbW3hlOp.9dd39b443c31.js} +1 -1
- codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CbW3hlOp.9dd39b443c31.js.gz +0 -0
- codex/static_root/assets/{confirm-dialog-D3_s2DQy.js → confirm-dialog-CbW3hlOp.js} +1 -1
- codex/static_root/assets/confirm-dialog-CbW3hlOp.js.br +0 -0
- codex/static_root/assets/confirm-dialog-CbW3hlOp.js.gz +0 -0
- codex/static_root/assets/{datetime-column-BxC1Li9e.3dc314b3295d.js → datetime-column-uSqKZU37.b157b0743db5.js} +1 -1
- codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js.br +0 -0
- codex/static_root/assets/datetime-column-uSqKZU37.b157b0743db5.js.gz +0 -0
- codex/static_root/assets/{datetime-column-BxC1Li9e.js → datetime-column-uSqKZU37.js} +1 -1
- codex/static_root/assets/datetime-column-uSqKZU37.js.br +0 -0
- codex/static_root/assets/datetime-column-uSqKZU37.js.gz +0 -0
- codex/static_root/assets/{filter-Bzk7x841.d0c3b602e62d.js → filter-CBl5KEsB.845a81573c2e.js} +1 -1
- codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js.br +0 -0
- codex/static_root/assets/filter-CBl5KEsB.845a81573c2e.js.gz +0 -0
- codex/static_root/assets/{filter-Bzk7x841.js → filter-CBl5KEsB.js} +1 -1
- codex/static_root/assets/filter-CBl5KEsB.js.br +0 -0
- codex/static_root/assets/filter-CBl5KEsB.js.gz +0 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js +1 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js.br +0 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.ecb6eee2e7a0.js.gz +0 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.js +1 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.js.br +0 -0
- codex/static_root/assets/flag-tab-CT8pqM4r.js.gz +0 -0
- codex/static_root/assets/{group-tab-5esH4lwX.a81fdd258117.js → group-tab-BOW9kigw.7e5007596367.js} +1 -1
- codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js.br +0 -0
- codex/static_root/assets/group-tab-BOW9kigw.7e5007596367.js.gz +0 -0
- codex/static_root/assets/{group-tab-5esH4lwX.js → group-tab-BOW9kigw.js} +1 -1
- codex/static_root/assets/group-tab-BOW9kigw.js.br +0 -0
- codex/static_root/assets/group-tab-BOW9kigw.js.gz +0 -0
- codex/static_root/assets/{http-error-BTOBfcGY.52ced6f28420.js → http-error-C6yuLApo.45cf99eb7a70.js} +1 -1
- codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.br +4 -0
- codex/static_root/assets/http-error-C6yuLApo.45cf99eb7a70.js.gz +0 -0
- codex/static_root/assets/{http-error-BTOBfcGY.js → http-error-C6yuLApo.js} +1 -1
- codex/static_root/assets/http-error-C6yuLApo.js.br +4 -0
- codex/static_root/assets/http-error-C6yuLApo.js.gz +0 -0
- codex/static_root/assets/{library-tab-DiPEdOF7.ece2d642a9dc.js → library-tab-D3WOtpE0.9af34e6e7235.js} +1 -1
- codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js.br +0 -0
- codex/static_root/assets/library-tab-D3WOtpE0.9af34e6e7235.js.gz +0 -0
- codex/static_root/assets/{library-tab-DiPEdOF7.js → library-tab-D3WOtpE0.js} +1 -1
- codex/static_root/assets/library-tab-D3WOtpE0.js.br +0 -0
- codex/static_root/assets/library-tab-D3WOtpE0.js.gz +0 -0
- codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js +6 -0
- codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js.br +0 -0
- codex/static_root/assets/main-CmjU2oTp.6a471f6900e5.js.gz +0 -0
- codex/static_root/assets/main-CmjU2oTp.js +6 -0
- codex/static_root/assets/main-CmjU2oTp.js.br +0 -0
- codex/static_root/assets/main-CmjU2oTp.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js +1 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.6e92d0555cd7.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.js +1 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-BH54_5f6.js.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-C45-onwe.4722195bb60b.css → pagination-toolbar-DGrxp2OD.css} +1 -1
- codex/static_root/assets/pagination-toolbar-DGrxp2OD.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGrxp2OD.css.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-C45-onwe.css → pagination-toolbar-DGrxp2OD.f960a624f04f.css} +1 -1
- codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-DGrxp2OD.f960a624f04f.css.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-CkIzuyx1.00c354a82e6e.js → pagination-toolbar-JH3Kbffr.451171f7ac33.js} +1 -1
- codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-JH3Kbffr.451171f7ac33.js.gz +0 -0
- codex/static_root/assets/{pagination-toolbar-CkIzuyx1.js → pagination-toolbar-JH3Kbffr.js} +1 -1
- codex/static_root/assets/pagination-toolbar-JH3Kbffr.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-JH3Kbffr.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-BjlRPuf4.0f056fa321b6.js → pdf-doc-BcRNpoaW.882f6e967869.js} +1 -1
- codex/static_root/assets/pdf-doc-BcRNpoaW.882f6e967869.js.br +0 -0
- codex/static_root/assets/pdf-doc-BcRNpoaW.882f6e967869.js.gz +0 -0
- codex/static_root/assets/{pdf-doc-BjlRPuf4.js → pdf-doc-BcRNpoaW.js} +1 -1
- codex/static_root/assets/pdf-doc-BcRNpoaW.js.br +0 -0
- codex/static_root/assets/pdf-doc-BcRNpoaW.js.gz +0 -0
- codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js +2 -0
- codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js.br +0 -0
- codex/static_root/assets/reader-DIPRg2VB.900370e097aa.js.gz +0 -0
- codex/static_root/assets/reader-DIPRg2VB.js +2 -0
- codex/static_root/assets/reader-DIPRg2VB.js.br +0 -0
- codex/static_root/assets/reader-DIPRg2VB.js.gz +0 -0
- codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css +1 -0
- codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css.br +0 -0
- codex/static_root/assets/reader-DveZZr9x.7b21b9f8f628.css.gz +0 -0
- codex/static_root/assets/reader-DveZZr9x.css +1 -0
- codex/static_root/assets/reader-DveZZr9x.css.br +0 -0
- codex/static_root/assets/reader-DveZZr9x.css.gz +0 -0
- codex/static_root/assets/{relation-chips-CUSatZET.js → relation-chips-3tTlR5QH.71f18bc92adc.js} +1 -1
- codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js.br +0 -0
- codex/static_root/assets/relation-chips-3tTlR5QH.71f18bc92adc.js.gz +0 -0
- codex/static_root/assets/{relation-chips-CUSatZET.a58031ff8141.js → relation-chips-3tTlR5QH.js} +1 -1
- codex/static_root/assets/relation-chips-3tTlR5QH.js.br +0 -0
- codex/static_root/assets/relation-chips-3tTlR5QH.js.gz +0 -0
- codex/static_root/assets/{settings-drawer-BSHTAsJ9.js → settings-drawer-BdyFhA_r.151f4c3061ed.js} +2 -2
- codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js.br +0 -0
- codex/static_root/assets/settings-drawer-BdyFhA_r.151f4c3061ed.js.gz +0 -0
- codex/static_root/assets/{settings-drawer-BSHTAsJ9.1d07ce084fc9.js → settings-drawer-BdyFhA_r.js} +2 -2
- codex/static_root/assets/settings-drawer-BdyFhA_r.js.br +0 -0
- codex/static_root/assets/settings-drawer-BdyFhA_r.js.gz +0 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js +1 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js.br +0 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.7557c71b4cfa.js.gz +0 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.js +1 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.js.br +0 -0
- codex/static_root/assets/stats-tab-DeKjwvmh.js.gz +0 -0
- codex/static_root/assets/{stats-tab-BXGisn5N.9b7a71e7fe28.css → stats-tab-DpfGsVX3.1cb66f2649a9.css} +1 -1
- codex/static_root/assets/stats-tab-DpfGsVX3.1cb66f2649a9.css.br +0 -0
- codex/static_root/assets/stats-tab-DpfGsVX3.1cb66f2649a9.css.gz +0 -0
- codex/static_root/assets/{stats-tab-BXGisn5N.css → stats-tab-DpfGsVX3.css} +1 -1
- codex/static_root/assets/stats-tab-DpfGsVX3.css.br +0 -0
- codex/static_root/assets/stats-tab-DpfGsVX3.css.gz +0 -0
- codex/static_root/assets/{task-tab-NORFAa9p.97e07e366ddd.js → task-tab-C8D0qRP_.d4ab174c69a3.js} +1 -1
- codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js.br +0 -0
- codex/static_root/assets/task-tab-C8D0qRP_.d4ab174c69a3.js.gz +0 -0
- codex/static_root/assets/{task-tab-NORFAa9p.js → task-tab-C8D0qRP_.js} +1 -1
- codex/static_root/assets/task-tab-C8D0qRP_.js.br +0 -0
- codex/static_root/assets/task-tab-C8D0qRP_.js.gz +0 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js +1 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js.br +0 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.8e5c1b9e52b0.js.gz +0 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.js +1 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.js.br +0 -0
- codex/static_root/assets/unauthorized-BHgBRF4z.js.gz +0 -0
- codex/static_root/assets/{unauthorized-muDsv-rC.css → unauthorized-BjhIc97q.728511c92cd0.css} +1 -1
- codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css.br +0 -0
- codex/static_root/assets/unauthorized-BjhIc97q.728511c92cd0.css.gz +0 -0
- codex/static_root/assets/{unauthorized-muDsv-rC.2166ec8b3a32.css → unauthorized-BjhIc97q.css} +1 -1
- codex/static_root/assets/unauthorized-BjhIc97q.css.br +0 -0
- codex/static_root/assets/unauthorized-BjhIc97q.css.gz +0 -0
- codex/static_root/assets/{user-tab-CHbyN1EW.e7206db08680.js → user-tab-BU31Z92y.35613c713faf.js} +1 -1
- codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js.br +0 -0
- codex/static_root/assets/user-tab-BU31Z92y.35613c713faf.js.gz +0 -0
- codex/static_root/assets/{user-tab-CHbyN1EW.js → user-tab-BU31Z92y.js} +1 -1
- codex/static_root/assets/user-tab-BU31Z92y.js.br +0 -0
- codex/static_root/assets/user-tab-BU31Z92y.js.gz +0 -0
- codex/static_root/js/choices-admin.8aa64c911203.json +1 -0
- codex/static_root/js/choices-admin.8aa64c911203.json.br +0 -0
- codex/static_root/js/choices-admin.8aa64c911203.json.gz +0 -0
- codex/static_root/js/choices-admin.json +1 -1
- codex/static_root/js/choices-admin.json.br +0 -0
- codex/static_root/js/choices-admin.json.gz +0 -0
- codex/static_root/manifest.45cb46e19686.json +635 -0
- codex/static_root/manifest.45cb46e19686.json.br +0 -0
- codex/static_root/manifest.45cb46e19686.json.gz +0 -0
- codex/static_root/manifest.json +248 -248
- codex/static_root/manifest.json.br +0 -0
- codex/static_root/manifest.json.gz +0 -0
- codex/static_root/staticfiles.json +1 -1
- codex/status_controller.py +10 -4
- codex/views/admin/tasks.py +46 -40
- codex/views/auth.py +15 -4
- codex/views/browser/annotations.py +94 -51
- codex/views/browser/base.py +1 -2
- codex/views/browser/browser.py +52 -21
- codex/views/browser/cover.py +8 -4
- codex/views/browser/filters/annotations.py +28 -6
- codex/views/browser/filters/search/__init__.py +1 -0
- codex/views/browser/filters/search/aliases.py +81 -0
- codex/views/browser/filters/search/field/__init__.py +1 -0
- codex/views/browser/filters/search/field/column.py +53 -0
- codex/views/browser/filters/search/field/expression.py +177 -0
- codex/views/browser/filters/search/field/filter.py +70 -0
- codex/views/browser/filters/search/field/optimize.py +71 -0
- codex/views/browser/filters/search/field/parse.py +187 -0
- codex/views/browser/filters/search/fts.py +38 -0
- codex/views/browser/filters/search/parse.py +220 -0
- codex/views/browser/order_by.py +8 -2
- codex/views/browser/page_in_bounds.py +88 -0
- codex/views/browser/paginate.py +28 -113
- codex/views/const.py +0 -1
- codex/views/opds/v1/feed.py +2 -1
- codex/views/opds/v2/feed.py +2 -1
- codex/views/opds/v2/links.py +1 -1
- codex/views/reader/books.py +1 -1
- codex/views/reader/page.py +3 -3
- {codex-1.6.19.dist-info → codex-1.7.0a0.dist-info}/METADATA +18 -10
- {codex-1.6.19.dist-info → codex-1.7.0a0.dist-info}/RECORD +321 -372
- codex/_vendor/__init__.py +0 -0
- codex/_vendor/django_haystack-3.2.1.dist-info/AUTHORS +0 -127
- codex/_vendor/django_haystack-3.2.1.dist-info/INSTALLER +0 -1
- codex/_vendor/django_haystack-3.2.1.dist-info/LICENSE +0 -31
- codex/_vendor/django_haystack-3.2.1.dist-info/METADATA +0 -98
- codex/_vendor/django_haystack-3.2.1.dist-info/RECORD +0 -97
- codex/_vendor/django_haystack-3.2.1.dist-info/REQUESTED +0 -0
- codex/_vendor/django_haystack-3.2.1.dist-info/WHEEL +0 -5
- codex/_vendor/django_haystack-3.2.1.dist-info/top_level.txt +0 -1
- codex/_vendor/haystack/__init__.py +0 -80
- codex/_vendor/haystack/admin.py +0 -163
- codex/_vendor/haystack/apps.py +0 -31
- codex/_vendor/haystack/backends/__init__.py +0 -1109
- codex/_vendor/haystack/backends/elasticsearch2_backend.py +0 -390
- codex/_vendor/haystack/backends/elasticsearch5_backend.py +0 -483
- codex/_vendor/haystack/backends/elasticsearch7_backend.py +0 -586
- codex/_vendor/haystack/backends/elasticsearch_backend.py +0 -1141
- codex/_vendor/haystack/backends/simple_backend.py +0 -132
- codex/_vendor/haystack/backends/solr_backend.py +0 -991
- codex/_vendor/haystack/backends/whoosh_backend.py +0 -1104
- codex/_vendor/haystack/constants.py +0 -57
- codex/_vendor/haystack/exceptions.py +0 -57
- codex/_vendor/haystack/fields.py +0 -562
- codex/_vendor/haystack/forms.py +0 -135
- codex/_vendor/haystack/generic_views.py +0 -141
- codex/_vendor/haystack/indexes.py +0 -548
- codex/_vendor/haystack/inputs.py +0 -169
- codex/_vendor/haystack/management/__init__.py +0 -0
- codex/_vendor/haystack/management/commands/__init__.py +0 -0
- codex/_vendor/haystack/management/commands/build_solr_schema.py +0 -187
- codex/_vendor/haystack/management/commands/clear_index.py +0 -67
- codex/_vendor/haystack/management/commands/haystack_info.py +0 -22
- codex/_vendor/haystack/management/commands/rebuild_index.py +0 -65
- codex/_vendor/haystack/management/commands/update_index.py +0 -438
- codex/_vendor/haystack/manager.py +0 -105
- codex/_vendor/haystack/models.py +0 -257
- codex/_vendor/haystack/panels.py +0 -89
- codex/_vendor/haystack/query.py +0 -771
- codex/_vendor/haystack/routers.py +0 -14
- codex/_vendor/haystack/signals.py +0 -88
- codex/_vendor/haystack/templates/panels/haystack.html +0 -33
- codex/_vendor/haystack/templates/search_configuration/schema.xml +0 -1056
- codex/_vendor/haystack/templates/search_configuration/solrconfig.xml +0 -1446
- codex/_vendor/haystack/templatetags/__init__.py +0 -0
- codex/_vendor/haystack/templatetags/highlight.py +0 -131
- codex/_vendor/haystack/templatetags/more_like_this.py +0 -119
- codex/_vendor/haystack/urls.py +0 -5
- codex/_vendor/haystack/utils/__init__.py +0 -84
- codex/_vendor/haystack/utils/app_loading.py +0 -34
- codex/_vendor/haystack/utils/geo.py +0 -71
- codex/_vendor/haystack/utils/highlighting.py +0 -165
- codex/_vendor/haystack/utils/loading.py +0 -374
- codex/_vendor/haystack/utils/log.py +0 -21
- codex/_vendor/haystack/version.py +0 -16
- codex/_vendor/haystack/views.py +0 -253
- codex/integrity.py +0 -492
- codex/librarian/search/merge.py +0 -86
- codex/librarian/search/version.py +0 -63
- codex/search/__init__.py +0 -1
- codex/search/backend.py +0 -524
- codex/search/backend_search.py +0 -229
- codex/search/engine.py +0 -33
- codex/search/indexes.py +0 -79
- codex/search/query.py +0 -67
- codex/search/writing.py +0 -180
- codex/static_root/assets/VCheckbox-Cko1sQK-.170726b3b8a1.js.br +0 -0
- codex/static_root/assets/VCheckbox-Cko1sQK-.170726b3b8a1.js.gz +0 -0
- codex/static_root/assets/VCheckbox-Cko1sQK-.js.br +0 -0
- codex/static_root/assets/VCheckbox-Cko1sQK-.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CO3-aqQL.c9b8062fd66f.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CO3-aqQL.c9b8062fd66f.js.gz +0 -0
- codex/static_root/assets/VCheckboxBtn-CO3-aqQL.js.br +0 -0
- codex/static_root/assets/VCheckboxBtn-CO3-aqQL.js.gz +0 -0
- codex/static_root/assets/VCombobox-Bjp6lffE.caf59fba486e.js.br +0 -0
- codex/static_root/assets/VCombobox-Bjp6lffE.caf59fba486e.js.gz +0 -0
- codex/static_root/assets/VCombobox-Bjp6lffE.js.br +0 -0
- codex/static_root/assets/VCombobox-Bjp6lffE.js.gz +0 -0
- codex/static_root/assets/VDialog-BkpVGB70.6eea3ca762a5.js.br +0 -0
- codex/static_root/assets/VDialog-BkpVGB70.6eea3ca762a5.js.gz +0 -0
- codex/static_root/assets/VDialog-BkpVGB70.js.br +0 -0
- codex/static_root/assets/VDialog-BkpVGB70.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-Ci2-j8XX.9c55db4ef49e.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-Ci2-j8XX.9c55db4ef49e.js.gz +0 -0
- codex/static_root/assets/VExpansionPanels-Ci2-j8XX.js.br +0 -0
- codex/static_root/assets/VExpansionPanels-Ci2-j8XX.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-D3Py5BfQ.a4f25edb86d3.js.br +0 -0
- codex/static_root/assets/VRadioGroup-D3Py5BfQ.a4f25edb86d3.js.gz +0 -0
- codex/static_root/assets/VRadioGroup-D3Py5BfQ.js.br +0 -0
- codex/static_root/assets/VRadioGroup-D3Py5BfQ.js.gz +0 -0
- codex/static_root/assets/VSelect-DtvZsYZz.e98745d858eb.js.br +0 -0
- codex/static_root/assets/VSelect-DtvZsYZz.e98745d858eb.js.gz +0 -0
- codex/static_root/assets/VSelect-DtvZsYZz.js.br +0 -0
- codex/static_root/assets/VSelect-DtvZsYZz.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-D6kmykQW.1e1fda62ceba.js.br +0 -0
- codex/static_root/assets/VSelectionControl-D6kmykQW.1e1fda62ceba.js.gz +0 -0
- codex/static_root/assets/VSelectionControl-D6kmykQW.js.br +0 -0
- codex/static_root/assets/VSelectionControl-D6kmykQW.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-UGZWxpF5.360bdefcd215.js.br +0 -0
- codex/static_root/assets/VSlideGroup-UGZWxpF5.360bdefcd215.js.gz +0 -0
- codex/static_root/assets/VSlideGroup-UGZWxpF5.js.br +0 -0
- codex/static_root/assets/VSlideGroup-UGZWxpF5.js.gz +0 -0
- codex/static_root/assets/VTable-DXH_yQ0o.1149f56ad566.js.br +0 -0
- codex/static_root/assets/VTable-DXH_yQ0o.1149f56ad566.js.gz +0 -0
- codex/static_root/assets/VTable-DXH_yQ0o.js.br +0 -0
- codex/static_root/assets/VTable-DXH_yQ0o.js.gz +0 -0
- codex/static_root/assets/VTextField-Blqy56_L.26d8761e0155.js.br +0 -0
- codex/static_root/assets/VTextField-Blqy56_L.26d8761e0155.js.gz +0 -0
- codex/static_root/assets/VTextField-Blqy56_L.js.br +0 -0
- codex/static_root/assets/VTextField-Blqy56_L.js.gz +0 -0
- codex/static_root/assets/VWindowItem-C8_ovV7e.afbc08414765.js.br +0 -0
- codex/static_root/assets/VWindowItem-C8_ovV7e.afbc08414765.js.gz +0 -0
- codex/static_root/assets/VWindowItem-C8_ovV7e.js.br +0 -0
- codex/static_root/assets/VWindowItem-C8_ovV7e.js.gz +0 -0
- codex/static_root/assets/admin-DTRn8bBs.d031ea42d8d0.js.br +0 -0
- codex/static_root/assets/admin-DTRn8bBs.d031ea42d8d0.js.gz +0 -0
- codex/static_root/assets/admin-DTRn8bBs.js.br +0 -0
- codex/static_root/assets/admin-DTRn8bBs.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BaXFOcru.b1a44b05f482.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BaXFOcru.b1a44b05f482.js.gz +0 -0
- codex/static_root/assets/admin-drawer-panel-BaXFOcru.js.br +0 -0
- codex/static_root/assets/admin-drawer-panel-BaXFOcru.js.gz +0 -0
- codex/static_root/assets/browser-BBpUyGmz.c1cb9e2d463b.js +0 -1
- codex/static_root/assets/browser-BBpUyGmz.c1cb9e2d463b.js.br +0 -0
- codex/static_root/assets/browser-BBpUyGmz.c1cb9e2d463b.js.gz +0 -0
- codex/static_root/assets/browser-BBpUyGmz.js +0 -1
- codex/static_root/assets/browser-BBpUyGmz.js.br +0 -0
- codex/static_root/assets/browser-BBpUyGmz.js.gz +0 -0
- codex/static_root/assets/browser-Binc3n9H.313722d27ca3.css +0 -1
- codex/static_root/assets/browser-Binc3n9H.313722d27ca3.css.br +0 -0
- codex/static_root/assets/browser-Binc3n9H.313722d27ca3.css.gz +0 -0
- codex/static_root/assets/browser-Binc3n9H.css +0 -1
- codex/static_root/assets/browser-Binc3n9H.css.br +0 -0
- codex/static_root/assets/browser-Binc3n9H.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-Cebek1-c.aff2975e31f8.css +0 -1
- codex/static_root/assets/change-password-dialog-Cebek1-c.aff2975e31f8.css.br +0 -0
- codex/static_root/assets/change-password-dialog-Cebek1-c.aff2975e31f8.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-Cebek1-c.css +0 -1
- codex/static_root/assets/change-password-dialog-Cebek1-c.css.br +0 -0
- codex/static_root/assets/change-password-dialog-Cebek1-c.css.gz +0 -0
- codex/static_root/assets/change-password-dialog-DlHoLhDF.76ab4a29bb9b.js +0 -1
- codex/static_root/assets/change-password-dialog-DlHoLhDF.76ab4a29bb9b.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DlHoLhDF.76ab4a29bb9b.js.gz +0 -0
- codex/static_root/assets/change-password-dialog-DlHoLhDF.js +0 -1
- codex/static_root/assets/change-password-dialog-DlHoLhDF.js.br +0 -0
- codex/static_root/assets/change-password-dialog-DlHoLhDF.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-D3_s2DQy.9dde66036c72.js.br +0 -0
- codex/static_root/assets/confirm-dialog-D3_s2DQy.9dde66036c72.js.gz +0 -0
- codex/static_root/assets/confirm-dialog-D3_s2DQy.js.br +0 -0
- codex/static_root/assets/confirm-dialog-D3_s2DQy.js.gz +0 -0
- codex/static_root/assets/datetime-column-BxC1Li9e.3dc314b3295d.js.br +0 -0
- codex/static_root/assets/datetime-column-BxC1Li9e.3dc314b3295d.js.gz +0 -0
- codex/static_root/assets/datetime-column-BxC1Li9e.js.br +0 -0
- codex/static_root/assets/datetime-column-BxC1Li9e.js.gz +0 -0
- codex/static_root/assets/filter-Bzk7x841.d0c3b602e62d.js.br +0 -0
- codex/static_root/assets/filter-Bzk7x841.d0c3b602e62d.js.gz +0 -0
- codex/static_root/assets/filter-Bzk7x841.js.br +0 -0
- codex/static_root/assets/filter-Bzk7x841.js.gz +0 -0
- codex/static_root/assets/flag-tab-C2bI5zq3.8f8c297600a6.js +0 -1
- codex/static_root/assets/flag-tab-C2bI5zq3.8f8c297600a6.js.br +0 -0
- codex/static_root/assets/flag-tab-C2bI5zq3.8f8c297600a6.js.gz +0 -0
- codex/static_root/assets/flag-tab-C2bI5zq3.js +0 -1
- codex/static_root/assets/flag-tab-C2bI5zq3.js.br +0 -0
- codex/static_root/assets/flag-tab-C2bI5zq3.js.gz +0 -0
- codex/static_root/assets/group-tab-5esH4lwX.a81fdd258117.js.br +0 -0
- codex/static_root/assets/group-tab-5esH4lwX.a81fdd258117.js.gz +0 -0
- codex/static_root/assets/group-tab-5esH4lwX.js.br +0 -0
- codex/static_root/assets/group-tab-5esH4lwX.js.gz +0 -0
- codex/static_root/assets/http-error-BTOBfcGY.52ced6f28420.js.br +0 -0
- codex/static_root/assets/http-error-BTOBfcGY.52ced6f28420.js.gz +0 -0
- codex/static_root/assets/http-error-BTOBfcGY.js.br +0 -0
- codex/static_root/assets/http-error-BTOBfcGY.js.gz +0 -0
- codex/static_root/assets/library-tab-DiPEdOF7.ece2d642a9dc.js.br +0 -0
- codex/static_root/assets/library-tab-DiPEdOF7.ece2d642a9dc.js.gz +0 -0
- codex/static_root/assets/library-tab-DiPEdOF7.js.br +0 -0
- codex/static_root/assets/library-tab-DiPEdOF7.js.gz +0 -0
- codex/static_root/assets/main-BPIPjzsc.66def8991e38.js +0 -6
- codex/static_root/assets/main-BPIPjzsc.66def8991e38.js.br +0 -0
- codex/static_root/assets/main-BPIPjzsc.66def8991e38.js.gz +0 -0
- codex/static_root/assets/main-BPIPjzsc.js +0 -6
- codex/static_root/assets/main-BPIPjzsc.js.br +0 -0
- codex/static_root/assets/main-BPIPjzsc.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-CiyC6Al9.278b9978f36f.js +0 -1
- codex/static_root/assets/pager-full-pdf-CiyC6Al9.278b9978f36f.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-CiyC6Al9.278b9978f36f.js.gz +0 -0
- codex/static_root/assets/pager-full-pdf-CiyC6Al9.js +0 -1
- codex/static_root/assets/pager-full-pdf-CiyC6Al9.js.br +0 -0
- codex/static_root/assets/pager-full-pdf-CiyC6Al9.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-C45-onwe.4722195bb60b.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-C45-onwe.4722195bb60b.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-C45-onwe.css.br +0 -0
- codex/static_root/assets/pagination-toolbar-C45-onwe.css.gz +0 -0
- codex/static_root/assets/pagination-toolbar-CkIzuyx1.00c354a82e6e.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-CkIzuyx1.00c354a82e6e.js.gz +0 -0
- codex/static_root/assets/pagination-toolbar-CkIzuyx1.js.br +0 -0
- codex/static_root/assets/pagination-toolbar-CkIzuyx1.js.gz +0 -0
- codex/static_root/assets/pdf-doc-BjlRPuf4.0f056fa321b6.js.br +0 -0
- codex/static_root/assets/pdf-doc-BjlRPuf4.0f056fa321b6.js.gz +0 -0
- codex/static_root/assets/pdf-doc-BjlRPuf4.js.br +0 -0
- codex/static_root/assets/pdf-doc-BjlRPuf4.js.gz +0 -0
- codex/static_root/assets/reader-_stAWL-4.5089e9144795.css +0 -1
- codex/static_root/assets/reader-_stAWL-4.5089e9144795.css.br +0 -0
- codex/static_root/assets/reader-_stAWL-4.5089e9144795.css.gz +0 -0
- codex/static_root/assets/reader-_stAWL-4.css +0 -1
- codex/static_root/assets/reader-_stAWL-4.css.br +0 -0
- codex/static_root/assets/reader-_stAWL-4.css.gz +0 -0
- codex/static_root/assets/reader-ucxnLi2K.d0fbce0f03c1.js +0 -2
- codex/static_root/assets/reader-ucxnLi2K.d0fbce0f03c1.js.br +0 -0
- codex/static_root/assets/reader-ucxnLi2K.d0fbce0f03c1.js.gz +0 -0
- codex/static_root/assets/reader-ucxnLi2K.js +0 -2
- codex/static_root/assets/reader-ucxnLi2K.js.br +0 -0
- codex/static_root/assets/reader-ucxnLi2K.js.gz +0 -0
- codex/static_root/assets/relation-chips-CUSatZET.a58031ff8141.js.br +0 -0
- codex/static_root/assets/relation-chips-CUSatZET.a58031ff8141.js.gz +0 -0
- codex/static_root/assets/relation-chips-CUSatZET.js.br +0 -0
- codex/static_root/assets/relation-chips-CUSatZET.js.gz +0 -0
- codex/static_root/assets/settings-drawer-BSHTAsJ9.1d07ce084fc9.js.br +0 -0
- codex/static_root/assets/settings-drawer-BSHTAsJ9.1d07ce084fc9.js.gz +0 -0
- codex/static_root/assets/settings-drawer-BSHTAsJ9.js.br +0 -0
- codex/static_root/assets/settings-drawer-BSHTAsJ9.js.gz +0 -0
- codex/static_root/assets/stats-tab-BXGisn5N.9b7a71e7fe28.css.br +0 -0
- codex/static_root/assets/stats-tab-BXGisn5N.9b7a71e7fe28.css.gz +0 -0
- codex/static_root/assets/stats-tab-BXGisn5N.css.br +0 -0
- codex/static_root/assets/stats-tab-BXGisn5N.css.gz +0 -0
- codex/static_root/assets/stats-tab-DKXVB2Cc.0a3de58bf5ee.js +0 -1
- codex/static_root/assets/stats-tab-DKXVB2Cc.0a3de58bf5ee.js.br +0 -0
- codex/static_root/assets/stats-tab-DKXVB2Cc.0a3de58bf5ee.js.gz +0 -0
- codex/static_root/assets/stats-tab-DKXVB2Cc.js +0 -1
- codex/static_root/assets/stats-tab-DKXVB2Cc.js.br +0 -0
- codex/static_root/assets/stats-tab-DKXVB2Cc.js.gz +0 -0
- codex/static_root/assets/task-tab-NORFAa9p.97e07e366ddd.js.br +0 -0
- codex/static_root/assets/task-tab-NORFAa9p.97e07e366ddd.js.gz +0 -0
- codex/static_root/assets/task-tab-NORFAa9p.js.br +0 -0
- codex/static_root/assets/task-tab-NORFAa9p.js.gz +0 -0
- codex/static_root/assets/unauthorized-RHaQZRfr.a234e9403f60.js +0 -1
- codex/static_root/assets/unauthorized-RHaQZRfr.a234e9403f60.js.br +0 -0
- codex/static_root/assets/unauthorized-RHaQZRfr.a234e9403f60.js.gz +0 -0
- codex/static_root/assets/unauthorized-RHaQZRfr.js +0 -1
- codex/static_root/assets/unauthorized-RHaQZRfr.js.br +0 -0
- codex/static_root/assets/unauthorized-RHaQZRfr.js.gz +0 -0
- codex/static_root/assets/unauthorized-muDsv-rC.2166ec8b3a32.css.br +0 -0
- codex/static_root/assets/unauthorized-muDsv-rC.2166ec8b3a32.css.gz +0 -0
- codex/static_root/assets/unauthorized-muDsv-rC.css.br +0 -0
- codex/static_root/assets/unauthorized-muDsv-rC.css.gz +0 -0
- codex/static_root/assets/user-tab-CHbyN1EW.e7206db08680.js.br +0 -0
- codex/static_root/assets/user-tab-CHbyN1EW.e7206db08680.js.gz +0 -0
- codex/static_root/assets/user-tab-CHbyN1EW.js.br +0 -0
- codex/static_root/assets/user-tab-CHbyN1EW.js.gz +0 -0
- codex/static_root/js/choices-admin.1a20a5648f20.json +0 -1
- codex/static_root/js/choices-admin.1a20a5648f20.json.br +0 -0
- codex/static_root/js/choices-admin.1a20a5648f20.json.gz +0 -0
- codex/static_root/manifest.0fe31a6cb99f.json +0 -635
- codex/static_root/manifest.0fe31a6cb99f.json.br +0 -0
- codex/static_root/manifest.0fe31a6cb99f.json.gz +0 -0
- codex/templates/search/indexes/codex/comic_text.txt +0 -47
- codex/views/browser/filters/search.py +0 -196
- {codex-1.6.19.dist-info → codex-1.7.0a0.dist-info}/LICENSE +0 -0
- {codex-1.6.19.dist-info → codex-1.7.0a0.dist-info}/WHEEL +0 -0
- {codex-1.6.19.dist-info → codex-1.7.0a0.dist-info}/entry_points.txt +0 -0
|
@@ -1,374 +0,0 @@
|
|
|
1
|
-
import copy
|
|
2
|
-
import inspect
|
|
3
|
-
import threading
|
|
4
|
-
import warnings
|
|
5
|
-
from collections import OrderedDict
|
|
6
|
-
|
|
7
|
-
from django.conf import settings
|
|
8
|
-
from django.core.exceptions import ImproperlyConfigured
|
|
9
|
-
from django.utils.module_loading import module_has_submodule
|
|
10
|
-
|
|
11
|
-
from ...haystack import constants
|
|
12
|
-
from ...haystack.exceptions import NotHandled, SearchFieldError
|
|
13
|
-
from ...haystack.utils import importlib
|
|
14
|
-
from ...haystack.utils.app_loading import haystack_get_app_modules
|
|
15
|
-
|
|
16
|
-
VENDOR_PREFIX = "codex._vendor."
|
|
17
|
-
|
|
18
|
-
def import_class(path):
|
|
19
|
-
if path.startswith("haystack"):
|
|
20
|
-
path = VENDOR_PREFIX + path
|
|
21
|
-
path_bits = path.split(".")
|
|
22
|
-
# Cut off the class name at the end.
|
|
23
|
-
class_name = path_bits.pop()
|
|
24
|
-
module_path = ".".join(path_bits)
|
|
25
|
-
module_itself = importlib.import_module(module_path)
|
|
26
|
-
|
|
27
|
-
if not hasattr(module_itself, class_name):
|
|
28
|
-
raise ImportError(
|
|
29
|
-
"The Python module '%s' has no '%s' class." % (module_path, class_name)
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
return getattr(module_itself, class_name)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
# Load the search backend.
|
|
36
|
-
def load_backend(full_backend_path):
|
|
37
|
-
"""
|
|
38
|
-
Loads a backend for interacting with the search engine.
|
|
39
|
-
|
|
40
|
-
Requires a ``backend_path``. It should be a string resembling a Python
|
|
41
|
-
import path, pointing to a ``BaseEngine`` subclass. The built-in options
|
|
42
|
-
available include::
|
|
43
|
-
|
|
44
|
-
* haystack.backends.solr.SolrEngine
|
|
45
|
-
* haystack.backends.xapian.XapianEngine (third-party)
|
|
46
|
-
* haystack.backends.whoosh.WhooshEngine
|
|
47
|
-
* haystack.backends.simple.SimpleEngine
|
|
48
|
-
|
|
49
|
-
If you've implemented a custom backend, you can provide the path to
|
|
50
|
-
your backend & matching ``Engine`` class. For example::
|
|
51
|
-
|
|
52
|
-
``myapp.search_backends.CustomSolrEngine``
|
|
53
|
-
|
|
54
|
-
"""
|
|
55
|
-
path_bits = full_backend_path.split(".")
|
|
56
|
-
|
|
57
|
-
if len(path_bits) < 2:
|
|
58
|
-
raise ImproperlyConfigured(
|
|
59
|
-
"The provided backend '%s' is not a complete Python path to a BaseEngine subclass."
|
|
60
|
-
% full_backend_path
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
return import_class(full_backend_path)
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def load_router(full_router_path):
|
|
67
|
-
"""
|
|
68
|
-
Loads a router for choosing which connection to use.
|
|
69
|
-
|
|
70
|
-
Requires a ``full_router_path``. It should be a string resembling a Python
|
|
71
|
-
import path, pointing to a ``BaseRouter`` subclass. The built-in options
|
|
72
|
-
available include::
|
|
73
|
-
|
|
74
|
-
* haystack.routers.DefaultRouter
|
|
75
|
-
|
|
76
|
-
If you've implemented a custom backend, you can provide the path to
|
|
77
|
-
your backend & matching ``Engine`` class. For example::
|
|
78
|
-
|
|
79
|
-
``myapp.search_routers.MasterSlaveRouter``
|
|
80
|
-
|
|
81
|
-
"""
|
|
82
|
-
path_bits = full_router_path.split(".")
|
|
83
|
-
|
|
84
|
-
if len(path_bits) < 2:
|
|
85
|
-
raise ImproperlyConfigured(
|
|
86
|
-
"The provided router '%s' is not a complete Python path to a BaseRouter subclass."
|
|
87
|
-
% full_router_path
|
|
88
|
-
)
|
|
89
|
-
|
|
90
|
-
return import_class(full_router_path)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
class ConnectionHandler:
|
|
94
|
-
def __init__(self, connections_info):
|
|
95
|
-
self.connections_info = connections_info
|
|
96
|
-
self.thread_local = threading.local()
|
|
97
|
-
self._index = None
|
|
98
|
-
|
|
99
|
-
def ensure_defaults(self, alias):
|
|
100
|
-
try:
|
|
101
|
-
conn = self.connections_info[alias]
|
|
102
|
-
except KeyError:
|
|
103
|
-
raise ImproperlyConfigured(
|
|
104
|
-
"The key '%s' isn't an available connection." % alias
|
|
105
|
-
)
|
|
106
|
-
|
|
107
|
-
if not conn.get("ENGINE"):
|
|
108
|
-
conn["ENGINE"] = "haystack.backends.simple_backend.SimpleEngine"
|
|
109
|
-
|
|
110
|
-
def __getitem__(self, key):
|
|
111
|
-
if not hasattr(self.thread_local, "connections"):
|
|
112
|
-
self.thread_local.connections = {}
|
|
113
|
-
elif key in self.thread_local.connections:
|
|
114
|
-
return self.thread_local.connections[key]
|
|
115
|
-
|
|
116
|
-
self.ensure_defaults(key)
|
|
117
|
-
self.thread_local.connections[key] = load_backend(
|
|
118
|
-
self.connections_info[key]["ENGINE"]
|
|
119
|
-
)(using=key)
|
|
120
|
-
return self.thread_local.connections[key]
|
|
121
|
-
|
|
122
|
-
def reload(self, key):
|
|
123
|
-
if not hasattr(self.thread_local, "connections"):
|
|
124
|
-
self.thread_local.connections = {}
|
|
125
|
-
try:
|
|
126
|
-
del self.thread_local.connections[key]
|
|
127
|
-
except KeyError:
|
|
128
|
-
pass
|
|
129
|
-
|
|
130
|
-
return self.__getitem__(key)
|
|
131
|
-
|
|
132
|
-
def all(self): # noqa A003
|
|
133
|
-
return [self[alias] for alias in self.connections_info]
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
class ConnectionRouter:
|
|
137
|
-
def __init__(self):
|
|
138
|
-
self._routers = None
|
|
139
|
-
|
|
140
|
-
@property
|
|
141
|
-
def routers(self):
|
|
142
|
-
if self._routers is None:
|
|
143
|
-
default_routers = ["haystack.routers.DefaultRouter"]
|
|
144
|
-
router_list = getattr(settings, "HAYSTACK_ROUTERS", default_routers)
|
|
145
|
-
# in case HAYSTACK_ROUTERS is empty, fallback to default routers
|
|
146
|
-
if not len(router_list):
|
|
147
|
-
router_list = default_routers
|
|
148
|
-
|
|
149
|
-
self._routers = []
|
|
150
|
-
for router_path in router_list:
|
|
151
|
-
router_class = load_router(router_path)
|
|
152
|
-
self._routers.append(router_class())
|
|
153
|
-
return self._routers
|
|
154
|
-
|
|
155
|
-
def _for_action(self, action, many, **hints):
|
|
156
|
-
conns = []
|
|
157
|
-
|
|
158
|
-
for router in self.routers:
|
|
159
|
-
if hasattr(router, action):
|
|
160
|
-
action_callable = getattr(router, action)
|
|
161
|
-
connection_to_use = action_callable(**hints)
|
|
162
|
-
|
|
163
|
-
if connection_to_use is not None:
|
|
164
|
-
if isinstance(connection_to_use, str):
|
|
165
|
-
conns.append(connection_to_use)
|
|
166
|
-
else:
|
|
167
|
-
conns.extend(connection_to_use)
|
|
168
|
-
if not many:
|
|
169
|
-
break
|
|
170
|
-
|
|
171
|
-
return conns
|
|
172
|
-
|
|
173
|
-
def for_write(self, **hints):
|
|
174
|
-
return self._for_action("for_write", True, **hints)
|
|
175
|
-
|
|
176
|
-
def for_read(self, **hints):
|
|
177
|
-
return self._for_action("for_read", False, **hints)[0]
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
class UnifiedIndex:
|
|
181
|
-
# Used to collect all the indexes into a cohesive whole.
|
|
182
|
-
def __init__(self, excluded_indexes=None):
|
|
183
|
-
self._indexes = {}
|
|
184
|
-
self.fields = OrderedDict()
|
|
185
|
-
self._built = False
|
|
186
|
-
self.excluded_indexes = excluded_indexes or []
|
|
187
|
-
self.excluded_indexes_ids = {}
|
|
188
|
-
self.document_field = constants.DOCUMENT_FIELD
|
|
189
|
-
self._fieldnames = {}
|
|
190
|
-
self._facet_fieldnames = {}
|
|
191
|
-
|
|
192
|
-
@property
|
|
193
|
-
def indexes(self):
|
|
194
|
-
warnings.warn(
|
|
195
|
-
"'UnifiedIndex.indexes' was deprecated in Haystack v2.3.0. Please use UnifiedIndex.get_indexes()."
|
|
196
|
-
)
|
|
197
|
-
return self._indexes
|
|
198
|
-
|
|
199
|
-
def collect_indexes(self):
|
|
200
|
-
indexes = []
|
|
201
|
-
|
|
202
|
-
for app_mod in haystack_get_app_modules():
|
|
203
|
-
try:
|
|
204
|
-
search_index_module = importlib.import_module(
|
|
205
|
-
"%s.search_indexes" % app_mod.__name__
|
|
206
|
-
)
|
|
207
|
-
except ImportError:
|
|
208
|
-
if module_has_submodule(app_mod, "search_indexes"):
|
|
209
|
-
raise
|
|
210
|
-
|
|
211
|
-
continue
|
|
212
|
-
|
|
213
|
-
for item_name, item in inspect.getmembers(
|
|
214
|
-
search_index_module, inspect.isclass
|
|
215
|
-
):
|
|
216
|
-
if getattr(item, "haystack_use_for_indexing", False) and getattr(
|
|
217
|
-
item, "get_model", None
|
|
218
|
-
):
|
|
219
|
-
# We've got an index. Check if we should be ignoring it.
|
|
220
|
-
class_path = "%s.search_indexes.%s" % (app_mod.__name__, item_name)
|
|
221
|
-
|
|
222
|
-
if (
|
|
223
|
-
class_path in self.excluded_indexes
|
|
224
|
-
or self.excluded_indexes_ids.get(item_name) == id(item)
|
|
225
|
-
):
|
|
226
|
-
self.excluded_indexes_ids[str(item_name)] = id(item)
|
|
227
|
-
continue
|
|
228
|
-
|
|
229
|
-
indexes.append(item())
|
|
230
|
-
|
|
231
|
-
return indexes
|
|
232
|
-
|
|
233
|
-
def reset(self):
|
|
234
|
-
self._indexes = {}
|
|
235
|
-
self.fields = OrderedDict()
|
|
236
|
-
self._built = False
|
|
237
|
-
self._fieldnames = {}
|
|
238
|
-
self._facet_fieldnames = {}
|
|
239
|
-
|
|
240
|
-
def build(self, indexes=None):
|
|
241
|
-
self.reset()
|
|
242
|
-
|
|
243
|
-
if indexes is None:
|
|
244
|
-
indexes = self.collect_indexes()
|
|
245
|
-
|
|
246
|
-
for index in indexes:
|
|
247
|
-
model = index.get_model()
|
|
248
|
-
|
|
249
|
-
if model in self._indexes:
|
|
250
|
-
raise ImproperlyConfigured(
|
|
251
|
-
"Model '%s' has more than one 'SearchIndex`` handling it. "
|
|
252
|
-
"Please exclude either '%s' or '%s' using the 'EXCLUDED_INDEXES' "
|
|
253
|
-
"setting defined in 'settings.HAYSTACK_CONNECTIONS'."
|
|
254
|
-
% (model, self._indexes[model], index)
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
self._indexes[model] = index
|
|
258
|
-
self.collect_fields(index)
|
|
259
|
-
|
|
260
|
-
self._built = True
|
|
261
|
-
|
|
262
|
-
def collect_fields(self, index):
|
|
263
|
-
for fieldname, field_object in index.fields.items():
|
|
264
|
-
if field_object.document is True:
|
|
265
|
-
if field_object.index_fieldname != self.document_field:
|
|
266
|
-
raise SearchFieldError(
|
|
267
|
-
"All 'SearchIndex' classes must use the same '%s' fieldname for the 'document=True' field. Offending index is '%s'."
|
|
268
|
-
% (self.document_field, index)
|
|
269
|
-
)
|
|
270
|
-
|
|
271
|
-
# Stow the index_fieldname so we don't have to get it the hard way again.
|
|
272
|
-
if (
|
|
273
|
-
fieldname in self._fieldnames
|
|
274
|
-
and field_object.index_fieldname != self._fieldnames[fieldname]
|
|
275
|
-
):
|
|
276
|
-
# We've already seen this field in the list. Raise an exception if index_fieldname differs.
|
|
277
|
-
raise SearchFieldError(
|
|
278
|
-
"All uses of the '%s' field need to use the same 'index_fieldname' attribute."
|
|
279
|
-
% fieldname
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
self._fieldnames[fieldname] = field_object.index_fieldname
|
|
283
|
-
|
|
284
|
-
# Stow the facet_fieldname so we don't have to look that up either.
|
|
285
|
-
if hasattr(field_object, "facet_for"):
|
|
286
|
-
if field_object.facet_for:
|
|
287
|
-
self._facet_fieldnames[field_object.facet_for] = fieldname
|
|
288
|
-
else:
|
|
289
|
-
self._facet_fieldnames[field_object.instance_name] = fieldname
|
|
290
|
-
|
|
291
|
-
# Copy the field in so we've got a unified schema.
|
|
292
|
-
if field_object.index_fieldname not in self.fields:
|
|
293
|
-
self.fields[field_object.index_fieldname] = field_object
|
|
294
|
-
self.fields[field_object.index_fieldname] = copy.copy(field_object)
|
|
295
|
-
else:
|
|
296
|
-
# If the field types are different, we can mostly
|
|
297
|
-
# safely ignore this. The exception is ``MultiValueField``,
|
|
298
|
-
# in which case we'll use it instead, copying over the
|
|
299
|
-
# values.
|
|
300
|
-
if field_object.is_multivalued:
|
|
301
|
-
old_field = self.fields[field_object.index_fieldname]
|
|
302
|
-
self.fields[field_object.index_fieldname] = field_object
|
|
303
|
-
self.fields[field_object.index_fieldname] = copy.copy(field_object)
|
|
304
|
-
|
|
305
|
-
# Switch it so we don't have to dupe the remaining
|
|
306
|
-
# checks.
|
|
307
|
-
field_object = old_field
|
|
308
|
-
|
|
309
|
-
# We've already got this field in the list. Ensure that
|
|
310
|
-
# what we hand back is a superset of all options that
|
|
311
|
-
# affect the schema.
|
|
312
|
-
if field_object.indexed is True:
|
|
313
|
-
self.fields[field_object.index_fieldname].indexed = True
|
|
314
|
-
|
|
315
|
-
if field_object.stored is True:
|
|
316
|
-
self.fields[field_object.index_fieldname].stored = True
|
|
317
|
-
|
|
318
|
-
if field_object.faceted is True:
|
|
319
|
-
self.fields[field_object.index_fieldname].faceted = True
|
|
320
|
-
|
|
321
|
-
if field_object.use_template is True:
|
|
322
|
-
self.fields[field_object.index_fieldname].use_template = True
|
|
323
|
-
|
|
324
|
-
if field_object.null is True:
|
|
325
|
-
self.fields[field_object.index_fieldname].null = True
|
|
326
|
-
|
|
327
|
-
def get_indexes(self):
|
|
328
|
-
if not self._built:
|
|
329
|
-
self.build()
|
|
330
|
-
|
|
331
|
-
return self._indexes
|
|
332
|
-
|
|
333
|
-
def get_indexed_models(self):
|
|
334
|
-
# Ensuring a list here since Python3 will give us an iterator
|
|
335
|
-
return list(self.get_indexes().keys())
|
|
336
|
-
|
|
337
|
-
def get_index_fieldname(self, field):
|
|
338
|
-
if not self._built:
|
|
339
|
-
self.build()
|
|
340
|
-
|
|
341
|
-
return self._fieldnames.get(field) or field
|
|
342
|
-
|
|
343
|
-
def get_index(self, model_klass):
|
|
344
|
-
|
|
345
|
-
indexes = self.get_indexes()
|
|
346
|
-
|
|
347
|
-
if model_klass not in indexes:
|
|
348
|
-
raise NotHandled("The model %s is not registered" % model_klass)
|
|
349
|
-
|
|
350
|
-
return indexes[model_klass]
|
|
351
|
-
|
|
352
|
-
def get_facet_fieldname(self, field):
|
|
353
|
-
if not self._built:
|
|
354
|
-
self.build()
|
|
355
|
-
|
|
356
|
-
for fieldname, field_object in self.fields.items():
|
|
357
|
-
if fieldname != field:
|
|
358
|
-
continue
|
|
359
|
-
|
|
360
|
-
if hasattr(field_object, "facet_for"):
|
|
361
|
-
if field_object.facet_for:
|
|
362
|
-
return field_object.facet_for
|
|
363
|
-
else:
|
|
364
|
-
return field_object.instance_name
|
|
365
|
-
else:
|
|
366
|
-
return self._facet_fieldnames.get(field) or field
|
|
367
|
-
|
|
368
|
-
return field
|
|
369
|
-
|
|
370
|
-
def all_searchfields(self):
|
|
371
|
-
if not self._built:
|
|
372
|
-
self.build()
|
|
373
|
-
|
|
374
|
-
return self.fields
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
from django.conf import settings
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def getLogger(name):
|
|
7
|
-
real_logger = logging.getLogger(name)
|
|
8
|
-
return LoggingFacade(real_logger)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class LoggingFacade:
|
|
12
|
-
def __init__(self, real_logger):
|
|
13
|
-
self.real_logger = real_logger
|
|
14
|
-
|
|
15
|
-
def noop(self, *args, **kwargs):
|
|
16
|
-
pass
|
|
17
|
-
|
|
18
|
-
def __getattr__(self, attr):
|
|
19
|
-
if getattr(settings, "HAYSTACK_LOGGING", True):
|
|
20
|
-
return getattr(self.real_logger, attr)
|
|
21
|
-
return self.noop
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
# file generated by setuptools_scm
|
|
2
|
-
# don't change, don't track in version control
|
|
3
|
-
TYPE_CHECKING = False
|
|
4
|
-
if TYPE_CHECKING:
|
|
5
|
-
from typing import Tuple, Union
|
|
6
|
-
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
|
-
else:
|
|
8
|
-
VERSION_TUPLE = object
|
|
9
|
-
|
|
10
|
-
version: str
|
|
11
|
-
__version__: str
|
|
12
|
-
__version_tuple__: VERSION_TUPLE
|
|
13
|
-
version_tuple: VERSION_TUPLE
|
|
14
|
-
|
|
15
|
-
__version__ = version = '3.2.1'
|
|
16
|
-
__version_tuple__ = version_tuple = (3, 2, 1)
|
codex/_vendor/haystack/views.py
DELETED
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
from django.conf import settings
|
|
2
|
-
from django.core.paginator import InvalidPage, Paginator
|
|
3
|
-
from django.http import Http404
|
|
4
|
-
from django.shortcuts import render
|
|
5
|
-
|
|
6
|
-
from ..haystack.forms import FacetedSearchForm, ModelSearchForm
|
|
7
|
-
from ..haystack.query import EmptySearchQuerySet
|
|
8
|
-
|
|
9
|
-
RESULTS_PER_PAGE = getattr(settings, "HAYSTACK_SEARCH_RESULTS_PER_PAGE", 20)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class SearchView:
|
|
13
|
-
template = "search/search.html"
|
|
14
|
-
extra_context = {}
|
|
15
|
-
query = ""
|
|
16
|
-
results = EmptySearchQuerySet()
|
|
17
|
-
request = None
|
|
18
|
-
form = None
|
|
19
|
-
results_per_page = RESULTS_PER_PAGE
|
|
20
|
-
|
|
21
|
-
def __init__(
|
|
22
|
-
self,
|
|
23
|
-
template=None,
|
|
24
|
-
load_all=True,
|
|
25
|
-
form_class=None,
|
|
26
|
-
searchqueryset=None,
|
|
27
|
-
results_per_page=None,
|
|
28
|
-
):
|
|
29
|
-
self.load_all = load_all
|
|
30
|
-
self.form_class = form_class
|
|
31
|
-
self.searchqueryset = searchqueryset
|
|
32
|
-
|
|
33
|
-
if form_class is None:
|
|
34
|
-
self.form_class = ModelSearchForm
|
|
35
|
-
|
|
36
|
-
if results_per_page is not None:
|
|
37
|
-
self.results_per_page = results_per_page
|
|
38
|
-
|
|
39
|
-
if template:
|
|
40
|
-
self.template = template
|
|
41
|
-
|
|
42
|
-
def __call__(self, request):
|
|
43
|
-
"""
|
|
44
|
-
Generates the actual response to the search.
|
|
45
|
-
|
|
46
|
-
Relies on internal, overridable methods to construct the response.
|
|
47
|
-
"""
|
|
48
|
-
self.request = request
|
|
49
|
-
|
|
50
|
-
self.form = self.build_form()
|
|
51
|
-
self.query = self.get_query()
|
|
52
|
-
self.results = self.get_results()
|
|
53
|
-
|
|
54
|
-
return self.create_response()
|
|
55
|
-
|
|
56
|
-
def build_form(self, form_kwargs=None):
|
|
57
|
-
"""
|
|
58
|
-
Instantiates the form the class should use to process the search query.
|
|
59
|
-
"""
|
|
60
|
-
data = None
|
|
61
|
-
kwargs = {"load_all": self.load_all}
|
|
62
|
-
if form_kwargs:
|
|
63
|
-
kwargs.update(form_kwargs)
|
|
64
|
-
|
|
65
|
-
if len(self.request.GET):
|
|
66
|
-
data = self.request.GET
|
|
67
|
-
|
|
68
|
-
if self.searchqueryset is not None:
|
|
69
|
-
kwargs["searchqueryset"] = self.searchqueryset
|
|
70
|
-
|
|
71
|
-
return self.form_class(data, **kwargs)
|
|
72
|
-
|
|
73
|
-
def get_query(self):
|
|
74
|
-
"""
|
|
75
|
-
Returns the query provided by the user.
|
|
76
|
-
|
|
77
|
-
Returns an empty string if the query is invalid.
|
|
78
|
-
"""
|
|
79
|
-
if self.form.is_valid():
|
|
80
|
-
return self.form.cleaned_data["q"]
|
|
81
|
-
|
|
82
|
-
return ""
|
|
83
|
-
|
|
84
|
-
def get_results(self):
|
|
85
|
-
"""
|
|
86
|
-
Fetches the results via the form.
|
|
87
|
-
|
|
88
|
-
Returns an empty list if there's no query to search with.
|
|
89
|
-
"""
|
|
90
|
-
return self.form.search()
|
|
91
|
-
|
|
92
|
-
def build_page(self):
|
|
93
|
-
"""
|
|
94
|
-
Paginates the results appropriately.
|
|
95
|
-
|
|
96
|
-
In case someone does not want to use Django's built-in pagination, it
|
|
97
|
-
should be a simple matter to override this method to do what they would
|
|
98
|
-
like.
|
|
99
|
-
"""
|
|
100
|
-
try:
|
|
101
|
-
page_no = int(self.request.GET.get("page", 1))
|
|
102
|
-
except (TypeError, ValueError):
|
|
103
|
-
raise Http404("Not a valid number for page.")
|
|
104
|
-
|
|
105
|
-
if page_no < 1:
|
|
106
|
-
raise Http404("Pages should be 1 or greater.")
|
|
107
|
-
|
|
108
|
-
start_offset = (page_no - 1) * self.results_per_page
|
|
109
|
-
self.results[start_offset : start_offset + self.results_per_page]
|
|
110
|
-
|
|
111
|
-
paginator = Paginator(self.results, self.results_per_page)
|
|
112
|
-
|
|
113
|
-
try:
|
|
114
|
-
page = paginator.page(page_no)
|
|
115
|
-
except InvalidPage:
|
|
116
|
-
raise Http404("No such page!")
|
|
117
|
-
|
|
118
|
-
return (paginator, page)
|
|
119
|
-
|
|
120
|
-
def extra_context(self):
|
|
121
|
-
"""
|
|
122
|
-
Allows the addition of more context variables as needed.
|
|
123
|
-
|
|
124
|
-
Must return a dictionary.
|
|
125
|
-
"""
|
|
126
|
-
return {}
|
|
127
|
-
|
|
128
|
-
def get_context(self):
|
|
129
|
-
(paginator, page) = self.build_page()
|
|
130
|
-
|
|
131
|
-
context = {
|
|
132
|
-
"query": self.query,
|
|
133
|
-
"form": self.form,
|
|
134
|
-
"page": page,
|
|
135
|
-
"paginator": paginator,
|
|
136
|
-
"suggestion": None,
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (
|
|
140
|
-
hasattr(self.results, "query")
|
|
141
|
-
and self.results.query.backend.include_spelling
|
|
142
|
-
):
|
|
143
|
-
context["suggestion"] = self.form.get_suggestion()
|
|
144
|
-
|
|
145
|
-
context.update(self.extra_context())
|
|
146
|
-
|
|
147
|
-
return context
|
|
148
|
-
|
|
149
|
-
def create_response(self):
|
|
150
|
-
"""
|
|
151
|
-
Generates the actual HttpResponse to send back to the user.
|
|
152
|
-
"""
|
|
153
|
-
|
|
154
|
-
context = self.get_context()
|
|
155
|
-
|
|
156
|
-
return render(self.request, self.template, context)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def search_view_factory(view_class=SearchView, *args, **kwargs):
|
|
160
|
-
def search_view(request):
|
|
161
|
-
return view_class(*args, **kwargs)(request)
|
|
162
|
-
|
|
163
|
-
return search_view
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
class FacetedSearchView(SearchView):
|
|
167
|
-
def __init__(self, *args, **kwargs):
|
|
168
|
-
# Needed to switch out the default form class.
|
|
169
|
-
if kwargs.get("form_class") is None:
|
|
170
|
-
kwargs["form_class"] = FacetedSearchForm
|
|
171
|
-
|
|
172
|
-
super().__init__(*args, **kwargs)
|
|
173
|
-
|
|
174
|
-
def build_form(self, form_kwargs=None):
|
|
175
|
-
if form_kwargs is None:
|
|
176
|
-
form_kwargs = {}
|
|
177
|
-
|
|
178
|
-
# This way the form can always receive a list containing zero or more
|
|
179
|
-
# facet expressions:
|
|
180
|
-
form_kwargs["selected_facets"] = self.request.GET.getlist("selected_facets")
|
|
181
|
-
|
|
182
|
-
return super().build_form(form_kwargs)
|
|
183
|
-
|
|
184
|
-
def extra_context(self):
|
|
185
|
-
extra = super().extra_context()
|
|
186
|
-
extra["request"] = self.request
|
|
187
|
-
extra["facets"] = self.results.facet_counts()
|
|
188
|
-
return extra
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
def basic_search(
|
|
192
|
-
request,
|
|
193
|
-
template="search/search.html",
|
|
194
|
-
load_all=True,
|
|
195
|
-
form_class=ModelSearchForm,
|
|
196
|
-
searchqueryset=None,
|
|
197
|
-
extra_context=None,
|
|
198
|
-
results_per_page=None,
|
|
199
|
-
):
|
|
200
|
-
"""
|
|
201
|
-
A more traditional view that also demonstrate an alternative
|
|
202
|
-
way to use Haystack.
|
|
203
|
-
|
|
204
|
-
Useful as an example of for basing heavily custom views off of.
|
|
205
|
-
|
|
206
|
-
Also has the benefit of thread-safety, which the ``SearchView`` class may
|
|
207
|
-
not be.
|
|
208
|
-
|
|
209
|
-
Template:: ``search/search.html``
|
|
210
|
-
Context::
|
|
211
|
-
* form
|
|
212
|
-
An instance of the ``form_class``. (default: ``ModelSearchForm``)
|
|
213
|
-
* page
|
|
214
|
-
The current page of search results.
|
|
215
|
-
* paginator
|
|
216
|
-
A paginator instance for the results.
|
|
217
|
-
* query
|
|
218
|
-
The query received by the form.
|
|
219
|
-
"""
|
|
220
|
-
query = ""
|
|
221
|
-
results = EmptySearchQuerySet()
|
|
222
|
-
|
|
223
|
-
if request.GET.get("q"):
|
|
224
|
-
form = form_class(request.GET, searchqueryset=searchqueryset, load_all=load_all)
|
|
225
|
-
|
|
226
|
-
if form.is_valid():
|
|
227
|
-
query = form.cleaned_data["q"]
|
|
228
|
-
results = form.search()
|
|
229
|
-
else:
|
|
230
|
-
form = form_class(searchqueryset=searchqueryset, load_all=load_all)
|
|
231
|
-
|
|
232
|
-
paginator = Paginator(results, results_per_page or RESULTS_PER_PAGE)
|
|
233
|
-
|
|
234
|
-
try:
|
|
235
|
-
page = paginator.page(int(request.GET.get("page", 1)))
|
|
236
|
-
except InvalidPage:
|
|
237
|
-
raise Http404("No such page of results!")
|
|
238
|
-
|
|
239
|
-
context = {
|
|
240
|
-
"form": form,
|
|
241
|
-
"page": page,
|
|
242
|
-
"paginator": paginator,
|
|
243
|
-
"query": query,
|
|
244
|
-
"suggestion": None,
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
if results.query.backend.include_spelling:
|
|
248
|
-
context["suggestion"] = form.get_suggestion()
|
|
249
|
-
|
|
250
|
-
if extra_context:
|
|
251
|
-
context.update(extra_context)
|
|
252
|
-
|
|
253
|
-
return render(request, template, context)
|