drf-haystack 1.9__tar.gz → 1.9.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. drf_haystack-1.9.3/PKG-INFO +101 -0
  2. {drf_haystack-1.9 → drf_haystack-1.9.3}/README.md +8 -7
  3. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/01_intro.rst +0 -1
  4. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/02_autocomplete.rst +0 -1
  5. drf_haystack-1.9.3/docs/conf.py +102 -0
  6. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/index.rst +16 -11
  7. {drf_haystack-1.9 → drf_haystack-1.9.3}/drf_haystack/__init__.py +1 -5
  8. {drf_haystack-1.9 → drf_haystack-1.9.3}/drf_haystack/fields.py +10 -22
  9. {drf_haystack-1.9 → drf_haystack-1.9.3}/drf_haystack/filters.py +21 -26
  10. {drf_haystack-1.9 → drf_haystack-1.9.3}/drf_haystack/generics.py +14 -16
  11. {drf_haystack-1.9 → drf_haystack-1.9.3}/drf_haystack/mixins.py +7 -13
  12. {drf_haystack-1.9 → drf_haystack-1.9.3}/drf_haystack/query.py +82 -81
  13. {drf_haystack-1.9 → drf_haystack-1.9.3}/drf_haystack/serializers.py +71 -76
  14. {drf_haystack-1.9 → drf_haystack-1.9.3}/drf_haystack/utils.py +2 -7
  15. {drf_haystack-1.9 → drf_haystack-1.9.3}/drf_haystack/viewsets.py +0 -5
  16. drf_haystack-1.9.3/pyproject.toml +84 -0
  17. drf_haystack-1.9.3/pyproject.toml.orig +78 -0
  18. drf_haystack-1.9.3/tests/constants.py +13 -0
  19. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mixins.py +1 -5
  20. drf_haystack-1.9.3/tests/mockapp/__init__.py +0 -0
  21. drf_haystack-1.9.3/tests/mockapp/admin.py +1 -0
  22. {drf_haystack-1.9/tests → drf_haystack-1.9.3/tests/mockapp}/apps.py +1 -4
  23. drf_haystack-1.9.3/tests/mockapp/migrations/0001_initial.py +23 -0
  24. drf_haystack-1.9.3/tests/mockapp/migrations/0002_mockperson.py +22 -0
  25. drf_haystack-1.9.3/tests/mockapp/migrations/0003_mockpet.py +23 -0
  26. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/migrations/0004_load_fixtures.py +8 -13
  27. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/migrations/0005_mockperson_birthdate.py +4 -6
  28. drf_haystack-1.9.3/tests/mockapp/migrations/0006_mockallfield.py +27 -0
  29. drf_haystack-1.9.3/tests/mockapp/migrations/__init__.py +0 -0
  30. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/models.py +26 -19
  31. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/search_indexes.py +10 -24
  32. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/serializers.py +19 -24
  33. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/templates/search/indexes/mockapp/mocklocation_text.txt +1 -1
  34. drf_haystack-1.9.3/tests/mockapp/templates/search/indexes/mockapp/mockpet_text.txt +1 -0
  35. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/views.py +7 -12
  36. drf_haystack-1.9.3/tests/settings.py +100 -0
  37. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/test_filters.py +93 -82
  38. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/test_serializers.py +130 -128
  39. drf_haystack-1.9.3/tests/test_utils.py +43 -0
  40. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/test_viewsets.py +27 -72
  41. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/urls.py +1 -6
  42. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/wsgi.py +2 -0
  43. drf_haystack-1.9/MANIFEST.in +0 -6
  44. drf_haystack-1.9/PKG-INFO +0 -25
  45. drf_haystack-1.9/Pipfile +0 -24
  46. drf_haystack-1.9/docs/conf.py +0 -178
  47. drf_haystack-1.9/drf_haystack.egg-info/PKG-INFO +0 -25
  48. drf_haystack-1.9/drf_haystack.egg-info/SOURCES.txt +0 -71
  49. drf_haystack-1.9/drf_haystack.egg-info/dependency_links.txt +0 -1
  50. drf_haystack-1.9/drf_haystack.egg-info/not-zip-safe +0 -1
  51. drf_haystack-1.9/drf_haystack.egg-info/requires.txt +0 -4
  52. drf_haystack-1.9/drf_haystack.egg-info/top_level.txt +0 -1
  53. drf_haystack-1.9/setup.cfg +0 -22
  54. drf_haystack-1.9/setup.py +0 -57
  55. drf_haystack-1.9/tests/__init__.py +0 -54
  56. drf_haystack-1.9/tests/constants.py +0 -17
  57. drf_haystack-1.9/tests/mockapp/admin.py +0 -3
  58. drf_haystack-1.9/tests/mockapp/migrations/0001_initial.py +0 -29
  59. drf_haystack-1.9/tests/mockapp/migrations/0002_mockperson.py +0 -27
  60. drf_haystack-1.9/tests/mockapp/migrations/0003_mockpet.py +0 -28
  61. drf_haystack-1.9/tests/mockapp/migrations/0006_mockallfield.py +0 -29
  62. drf_haystack-1.9/tests/mockapp/templates/search/indexes/mockapp/mockpet_text.txt +0 -1
  63. drf_haystack-1.9/tests/run_tests.py +0 -29
  64. drf_haystack-1.9/tests/settings.py +0 -122
  65. drf_haystack-1.9/tests/test_utils.py +0 -55
  66. drf_haystack-1.9/tox.ini +0 -427
  67. {drf_haystack-1.9 → drf_haystack-1.9.3}/LICENSE.txt +0 -0
  68. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/03_geospatial.rst +0 -0
  69. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/04_highlighting.rst +0 -0
  70. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/05_more_like_this.rst +0 -0
  71. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/06_term_boost.rst +0 -0
  72. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/07_faceting.rst +0 -0
  73. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/08_permissions.rst +0 -0
  74. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/09_multiple_indexes.rst +0 -0
  75. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/10_tips_n_tricks.rst +0 -0
  76. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/Makefile +0 -0
  77. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/apidoc/drf_haystack.rst +0 -0
  78. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/apidoc/modules.rst +0 -0
  79. {drf_haystack-1.9 → drf_haystack-1.9.3}/docs/make.bat +0 -0
  80. {drf_haystack-1.9 → drf_haystack-1.9.3}/drf_haystack/constants.py +0 -0
  81. {drf_haystack-1.9/tests/mockapp → drf_haystack-1.9.3/tests}/__init__.py +0 -0
  82. /drf_haystack-1.9/tests/mockapp/migrations/__init__.py → /drf_haystack-1.9.3/tests/logs/.gitkeep +0 -0
  83. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/fixtures/mockallfield.json +0 -0
  84. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/fixtures/mocklocation.json +0 -0
  85. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/fixtures/mockperson.json +0 -0
  86. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/fixtures/mockpet.json +0 -0
  87. {drf_haystack-1.9 → drf_haystack-1.9.3}/tests/mockapp/templates/search/indexes/mockapp/mockperson_text.txt +0 -0
@@ -0,0 +1,101 @@
1
+ Metadata-Version: 2.4
2
+ Name: drf-haystack
3
+ Version: 1.9.3
4
+ Summary: Makes Haystack play nice with Django REST Framework
5
+ Author: Dhaval Gojiya, Rolf Håvard Blindheim, Ülgen Sarıkavak
6
+ Author-email: Dhaval Gojiya <dhavalgojiya10@gmail.com>, Rolf Håvard Blindheim <rhblind@gmail.com>, Ülgen Sarıkavak <foss@ulgenwanders.net>
7
+ License-Expression: MIT
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Environment :: Web Environment
10
+ Classifier: Framework :: Django
11
+ Classifier: Framework :: Django :: 5.2
12
+ Classifier: Framework :: Django :: 6.0
13
+ Classifier: Framework :: Django :: 6.1
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Classifier: Topic :: Internet :: WWW/HTTP :: Indexing/Search
22
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
+ Requires-Dist: django>=5.2,<6.2
24
+ Requires-Dist: django-haystack>=3.3.0,<4
25
+ Requires-Dist: djangorestframework>=3.16
26
+ Requires-Dist: python-dateutil
27
+ Requires-Python: >=3.11, <3.15
28
+ Project-URL: Documentation, https://drf-haystack.readthedocs.io
29
+ Project-URL: Homepage, https://github.com/django-commons/drf-haystack
30
+ Project-URL: Issues, https://github.com/django-commons/drf-haystack/issues
31
+ Project-URL: Repository, https://github.com/django-commons/drf-haystack.git
32
+ Description-Content-Type: text/markdown
33
+
34
+ Haystack for Django REST Framework
35
+ ==================================
36
+
37
+ Build status
38
+ ------------
39
+
40
+ [![Coverage Status](https://coveralls.io/repos/github/django-commons/drf-haystack/badge.svg?branch=main)](https://coveralls.io/github/django-commons/drf-haystack?branch=main)
41
+ [![PyPI version](https://badge.fury.io/py/drf-haystack.svg)](https://badge.fury.io/py/drf-haystack)
42
+ [![Documentation Status](https://readthedocs.org/projects/drf-haystack/badge/?version=latest)](http://drf-haystack.readthedocs.io/en/latest/?badge=latest)
43
+
44
+
45
+ About
46
+ -----
47
+
48
+ Small library which tries to simplify integration of Haystack with Django REST Framework.
49
+ Fresh [documentation available](https://drf-haystack.readthedocs.io/en/latest/) on Read the docs!
50
+
51
+ Supported versions
52
+ ------------------
53
+
54
+ - Python >=3.11, <3.15
55
+ - Django >=5.2, <6.2
56
+ - Haystack >=3.3.0, <4
57
+ - Django REST Framework >=3.16
58
+ - Elasticsearch >=7.0.0, <8
59
+
60
+
61
+ Installation
62
+ ------------
63
+
64
+ $ pip install drf-haystack
65
+
66
+ Supported features
67
+ ------------------
68
+ We aim to support most features Haystack does (or at least those which can be used in a REST API).
69
+ Currently, we support:
70
+
71
+ - Autocomplete
72
+ - Boost (Experimental)
73
+ - Faceting
74
+ - Geo Spatial Search
75
+ - Highlighting
76
+ - More Like This
77
+
78
+ Show me more!
79
+ -------------
80
+
81
+ ```python
82
+ from drf_haystack.serializers import HaystackSerializer
83
+ from drf_haystack.viewsets import HaystackViewSet
84
+
85
+ from myapp.search_indexes import PersonIndex # You would define this Index normally as per Haystack's documentation
86
+
87
+
88
+ # Serializer
89
+ class PersonSearchSerializer(HaystackSerializer):
90
+ class Meta:
91
+ index_classes = [PersonIndex]
92
+ fields = ["firstname", "lastname", "full_name"]
93
+
94
+
95
+ # ViewSet
96
+ class PersonSearchViewSet(HaystackViewSet):
97
+ index_models = [Person]
98
+ serializer_class = PersonSerializer
99
+ ```
100
+
101
+ That's it, you're good to go. Hook it up to a DRF router and happy searching!
@@ -4,8 +4,7 @@ Haystack for Django REST Framework
4
4
  Build status
5
5
  ------------
6
6
 
7
- [![Build Status](https://travis-ci.org/rhblind/drf-haystack.svg?branch=master)](https://travis-ci.org/rhblind/drf-haystack)
8
- [![Coverage Status](https://coveralls.io/repos/github/rhblind/drf-haystack/badge.svg?branch=master)](https://coveralls.io/github/rhblind/drf-haystack?branch=master)
7
+ [![Coverage Status](https://coveralls.io/repos/github/django-commons/drf-haystack/badge.svg?branch=main)](https://coveralls.io/github/django-commons/drf-haystack?branch=main)
9
8
  [![PyPI version](https://badge.fury.io/py/drf-haystack.svg)](https://badge.fury.io/py/drf-haystack)
10
9
  [![Documentation Status](https://readthedocs.org/projects/drf-haystack/badge/?version=latest)](http://drf-haystack.readthedocs.io/en/latest/?badge=latest)
11
10
 
@@ -19,11 +18,11 @@ Fresh [documentation available](https://drf-haystack.readthedocs.io/en/latest/)
19
18
  Supported versions
20
19
  ------------------
21
20
 
22
- - Python 3.7 and above
23
- - Django >=2.2,<5.2
24
- - Haystack >=2.8,<3.4
25
- - Django REST Framework >=3.12.0,<3.16
26
- - elasticsearch >=2.0.0,<=8.3.3,
21
+ - Python >=3.11, <3.15
22
+ - Django >=5.2, <6.2
23
+ - Haystack >=3.3.0, <4
24
+ - Django REST Framework >=3.16
25
+ - Elasticsearch >=7.0.0, <8
27
26
 
28
27
 
29
28
  Installation
@@ -52,12 +51,14 @@ from drf_haystack.viewsets import HaystackViewSet
52
51
 
53
52
  from myapp.search_indexes import PersonIndex # You would define this Index normally as per Haystack's documentation
54
53
 
54
+
55
55
  # Serializer
56
56
  class PersonSearchSerializer(HaystackSerializer):
57
57
  class Meta:
58
58
  index_classes = [PersonIndex]
59
59
  fields = ["firstname", "lastname", "full_name"]
60
60
 
61
+
61
62
  # ViewSet
62
63
  class PersonSearchViewSet(HaystackViewSet):
63
64
  index_models = [Person]
@@ -209,4 +209,3 @@ The default keyword is ``not``, but is configurable via settings using ``DRF_HAY
209
209
  http://example.com/api/v1/location/search/?city__not=Oslo
210
210
  http://example.com/api/v1/location/search/?city__not__contains=Los
211
211
  http://example.com/api/v1/location/search/?city__contains=Los&city__not__contains=Angeles
212
-
@@ -45,4 +45,3 @@ An example using the autocomplete filter might look something like this.
45
45
  index_models = [Location]
46
46
  serializer_class = AutocompleteSerializer
47
47
  filter_backends = [HaystackAutocompleteFilter]
48
-
@@ -0,0 +1,102 @@
1
+ import os
2
+ import sys
3
+ from datetime import UTC, datetime
4
+ from pathlib import Path
5
+
6
+ import django
7
+
8
+ from drf_haystack import __version__
9
+
10
+ # If extensions (or modules to document with autodoc) are in another directory,
11
+ # add these directories to sys.path here. If the directory is relative to the
12
+ # documentation root, use os.path.abspath to make it absolute, like shown here.
13
+ sys.path.insert(0, str(Path("..").resolve()))
14
+ os.environ["RUNTIME_ENV"] = "TESTSUITE"
15
+ os.environ["DJANGO_SETTINGS_MODULE"] = "tests.settings"
16
+
17
+ django.setup()
18
+
19
+
20
+ # -- General configuration ------------------------------------------------
21
+
22
+ # Add any Sphinx extension module names here, as strings. They can be
23
+ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
24
+ # ones.
25
+ extensions = [
26
+ "sphinx.ext.autodoc",
27
+ "sphinx.ext.intersphinx",
28
+ "sphinx.ext.extlinks",
29
+ # TODO: Is this still needed?
30
+ "sphinx.ext.todo",
31
+ "sphinx.ext.viewcode",
32
+ ]
33
+
34
+ # Add any paths that contain templates here, relative to this directory.
35
+ templates_path = ["_templates"]
36
+
37
+ # The suffix(es) of source filenames.
38
+ # You can specify multiple suffix as a list of string:
39
+ #
40
+ # source_suffix = ['.rst', '.md']
41
+ source_suffix = ".rst"
42
+
43
+ # The master toctree document.
44
+ master_doc = "index"
45
+
46
+ # General information about the project.
47
+ project = "drf_haystack"
48
+ copyright = f"{datetime.now(tz=UTC).date().year}, Rolf Håvard Blindheim"
49
+ author = "Rolf Håvard Blindheim"
50
+
51
+ # The version info for the project you're documenting, acts as replacement for
52
+ # |version| and |release|, also used in various other places throughout the
53
+ # built documents.
54
+ #
55
+ # The full version, including alpha/beta/rc tags.
56
+ version = release = __version__
57
+
58
+ # The language for content autogenerated by Sphinx. Refer to documentation
59
+ # for a list of supported languages.
60
+ #
61
+ # This is also used if you do content translation via gettext catalogs.
62
+ # Usually you set "language" from the command line for these cases.
63
+ language = "en"
64
+
65
+ # List of patterns, relative to source directory, that match files and
66
+ # directories to ignore when looking for source files.
67
+ # This patterns also effect to html_static_path and html_extra_path
68
+ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
69
+
70
+ # The name of the Pygments (syntax highlighting) style to use.
71
+ pygments_style = "sphinx"
72
+
73
+ # If true, `todo` and `todoList` produce output, else they produce nothing.
74
+ todo_include_todos = True
75
+
76
+
77
+ # -- Options for HTML output ----------------------------------------------
78
+
79
+ # The theme to use for HTML and HTML Help pages. See the documentation for
80
+ # a list of builtin themes.
81
+ #
82
+ html_theme = "sphinx_rtd_theme"
83
+
84
+
85
+ # -- Options for HTMLHelp output ------------------------------------------
86
+
87
+ # Output file base name for HTML help builder.
88
+ htmlhelp_basename = "drfhaystackdoc"
89
+
90
+ # Example configuration for intersphinx: refer to the Python standard library.
91
+ intersphinx_mapping = {
92
+ "python": ("https://docs.python.org/", None),
93
+ "django": ("https://django.readthedocs.io/en/latest/", None),
94
+ "haystack": ("https://django-haystack.readthedocs.io/en/latest/", None),
95
+ }
96
+
97
+ # Configurations for extlinks
98
+ extlinks = {
99
+ "drf-pr": ("https://github.com/django-commons/drf-haystack/pull/%s", "PR#%s"),
100
+ "drf-issue": ("https://github.com/django-commons/drf-haystack/issues/%s", "#%s"),
101
+ "haystack-issue": ("https://github.com/django-haystack/django-haystack/issues/%s", "#%s"),
102
+ }
@@ -28,7 +28,7 @@ Features
28
28
 
29
29
  Supported Python and Django versions:
30
30
 
31
- - Python 3.6+
31
+ - Python >=3.11, <3.15
32
32
  - `All supported versions of Django <https://www.djangoproject.com/download/#supported-versions>`_
33
33
 
34
34
 
@@ -44,8 +44,8 @@ It's in the cheese shop!
44
44
  Requirements
45
45
  ============
46
46
  - A Supported Django install
47
- - Django REST Framework v3.2.0 and later
48
- - Haystack v2.5 and later
47
+ - Django REST Framework v3.16 and later
48
+ - Haystack v3.3.0 and later, below v4
49
49
  - A supported search engine such as Solr, Elasticsearch, Whoosh, etc.
50
50
  - Python bindings for the chosen backend (see below).
51
51
  - (geopy and libgeos if you want to use geo spatial filtering)
@@ -58,18 +58,17 @@ You will also need to install python bindings for the search engine you'll use.
58
58
  Elasticsearch
59
59
  .............
60
60
 
61
- See haystack `Elasticsearch <https://django-haystack.readthedocs.io/en/v2.4.1/installing_search_engines.html#elasticsearch>`_
61
+ See haystack `Elasticsearch <https://django-haystack.readthedocs.io/en/v3.3.0/installing_search_engines.html#elasticsearch>`_
62
62
  docs for details
63
63
 
64
64
  .. code-block:: none
65
65
 
66
- $ pip install elasticsearch<2.0.0 # For Elasticsearch 1.x
67
- $ pip install elasticsearch>=2.0.0,<3.0.0 # For Elasticsearch 2.x
66
+ $ pip install elasticsearch>=7.0.0,<8.0.0 # For Elasticsearch 7.x
68
67
 
69
68
  Solr
70
69
  ....
71
70
 
72
- See haystack `Solr <https://django-haystack.readthedocs.io/en/v2.4.1/installing_search_engines.html#solr>`_
71
+ See haystack `Solr <https://django-haystack.readthedocs.io/en/v3.3.0/installing_search_engines.html#solr>`_
73
72
  docs for details.
74
73
 
75
74
  .. code-block:: none
@@ -79,7 +78,7 @@ docs for details.
79
78
  Whoosh
80
79
  ......
81
80
 
82
- See haystack `Whoosh <https://django-haystack.readthedocs.io/en/v2.4.1/installing_search_engines.html#whoosh>`_
81
+ See haystack `Whoosh <https://django-haystack.readthedocs.io/en/v3.3.0/installing_search_engines.html#whoosh>`_
83
82
  docs for details.
84
83
 
85
84
  .. code-block:: none
@@ -89,7 +88,7 @@ docs for details.
89
88
  Xapian
90
89
  ......
91
90
 
92
- See haystack `Xapian <https://django-haystack.readthedocs.io/en/v2.4.1/installing_search_engines.html#xapian>`_
91
+ See haystack `Xapian <https://django-haystack.readthedocs.io/en/v3.3.0/installing_search_engines.html#xapian>`_
93
92
  docs for details.
94
93
 
95
94
 
@@ -100,14 +99,20 @@ This library has mainly been written by `me <https://github.com/rhblind>`_ while
100
99
  at `Inonit <https://github.com/inonit>`_. I have also had some help from these amazing people!
101
100
  Thanks guys!
102
101
 
103
- - See the full list of `contributors <https://github.com/rhblind/drf-haystack/graphs/contributors>`_.
102
+ - See the full list of `contributors <https://github.com/django-commons/drf-haystack/graphs/contributors>`_.
104
103
 
105
104
  Changelog
106
105
  =========
107
106
 
107
+ v1.9.1
108
+ ------
109
+ *Release date: 2024-11-05*
110
+
111
+ - Add deprecation warning about potential future sunsetting of the project, due to lack of active maintainers.
112
+
108
113
  v1.9
109
114
  ------
110
- *Release date: 2023-10-04*
115
+ *Release date: 2024-11-04*
111
116
 
112
117
  - Return an empty query object instead of an empty list when no filter is passed (:drf-issue:`202`).
113
118
  - add "id" as an optional value of the serializer fields returning the haystack internal id (:drf-issue:`193`).
@@ -1,9 +1,5 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- from __future__ import unicode_literals
4
-
5
1
  __title__ = "drf-haystack"
6
- __version__ = "1.9"
2
+ __version__ = "1.9.3"
7
3
  __author__ = "Rolf Haavard Blindheim"
8
4
  __license__ = "MIT License"
9
5
 
@@ -1,17 +1,12 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- from __future__ import absolute_import, unicode_literals
4
-
5
- import six
6
1
  from rest_framework import fields
7
2
 
8
3
 
9
- class DRFHaystackFieldMixin(object):
4
+ class DRFHaystackFieldMixin:
10
5
  prefix_field_names = False
11
6
 
12
7
  def __init__(self, **kwargs):
13
- self.prefix_field_names = kwargs.pop('prefix_field_names', False)
14
- super(DRFHaystackFieldMixin, self).__init__(**kwargs)
8
+ self.prefix_field_names = kwargs.pop("prefix_field_names", False)
9
+ super().__init__(**kwargs)
15
10
 
16
11
  def bind(self, field_name, parent):
17
12
  """
@@ -25,10 +20,9 @@ class DRFHaystackFieldMixin(object):
25
20
  # 'source' argument has been used. For example:
26
21
  # my_field = serializer.CharField(source='my_field')
27
22
  assert self.source != field_name, (
28
- "It is redundant to specify `source='%s'` on field '%s' in "
29
- "serializer '%s', because it is the same as the field name. "
30
- "Remove the `source` keyword argument." %
31
- (field_name, self.__class__.__name__, parent.__class__.__name__)
23
+ f"It is redundant to specify `source='{field_name}'` on field '{self.__class__.__name__}' in "
24
+ f"serializer '{parent.__class__.__name__}', because it is the same as the field name. "
25
+ "Remove the `source` keyword argument."
32
26
  )
33
27
 
34
28
  self.field_name = field_name
@@ -36,7 +30,7 @@ class DRFHaystackFieldMixin(object):
36
30
 
37
31
  # `self.label` should default to being based on the field name.
38
32
  if self.label is None:
39
- self.label = field_name.replace('_', ' ').capitalize()
33
+ self.label = field_name.replace("_", " ").capitalize()
40
34
 
41
35
  # self.source should default to being the same as the field name.
42
36
  if self.source is None:
@@ -44,10 +38,10 @@ class DRFHaystackFieldMixin(object):
44
38
 
45
39
  # self.source_attrs is a list of attributes that need to be looked up
46
40
  # when serializing the instance, or populating the validated data.
47
- if self.source == '*':
41
+ if self.source == "*":
48
42
  self.source_attrs = []
49
43
  else:
50
- self.source_attrs = self.source.split('.')
44
+ self.source_attrs = self.source.split(".")
51
45
 
52
46
  def convert_field_name(self, field_name):
53
47
  if not self.prefix_field_names:
@@ -95,11 +89,7 @@ class FacetDictField(fields.DictField):
95
89
  """
96
90
 
97
91
  def to_representation(self, value):
98
- return dict(
99
- [(six.text_type(key), self.child.to_representation(key, val))
100
- for key, val in value.items()
101
- ]
102
- )
92
+ return {str(key): self.child.to_representation(key, val) for key, val in value.items()}
103
93
 
104
94
 
105
95
  class FacetListField(fields.ListField):
@@ -110,5 +100,3 @@ class FacetListField(fields.ListField):
110
100
 
111
101
  def to_representation(self, key, data):
112
102
  return [self.child.to_representation(key, item) for item in data]
113
-
114
-
@@ -1,16 +1,11 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- from __future__ import absolute_import, unicode_literals
4
-
5
1
  import operator
6
- import six
7
2
  from functools import reduce
8
3
 
9
4
  from django.core.exceptions import ImproperlyConfigured
10
5
  from haystack.query import SearchQuerySet
11
6
  from rest_framework.filters import BaseFilterBackend, OrderingFilter
12
7
 
13
- from drf_haystack.query import BoostQueryBuilder, FilterQueryBuilder, FacetQueryBuilder, SpatialQueryBuilder
8
+ from drf_haystack.query import BoostQueryBuilder, FacetQueryBuilder, FilterQueryBuilder, SpatialQueryBuilder
14
9
 
15
10
 
16
11
  class BaseHaystackFilterBackend(BaseFilterBackend):
@@ -44,7 +39,7 @@ class BaseHaystackFilterBackend(BaseFilterBackend):
44
39
  Get the query builder instance and return constructed query filters.
45
40
  """
46
41
  query_builder = self.get_query_builder(backend=self, view=view)
47
- return query_builder.build_query(**(filters if filters else {}))
42
+ return query_builder.build_query(**(filters or {}))
48
43
 
49
44
  def process_filters(self, filters, queryset, view):
50
45
  """
@@ -61,7 +56,7 @@ class BaseHaystackFilterBackend(BaseFilterBackend):
61
56
  return self.apply_filters(
62
57
  queryset=queryset,
63
58
  applicable_filters=self.process_filters(applicable_filters, queryset, view),
64
- applicable_exclusions=self.process_filters(applicable_exclusions, queryset, view)
59
+ applicable_exclusions=self.process_filters(applicable_exclusions, queryset, view),
65
60
  )
66
61
 
67
62
  def get_query_builder(self, *args, **kwargs):
@@ -81,8 +76,8 @@ class BaseHaystackFilterBackend(BaseFilterBackend):
81
76
  methods of building the query sent to the search engine backend.
82
77
  """
83
78
  assert self.query_builder_class is not None, (
84
- "'%s' should either include a `query_builder_class` attribute, "
85
- "or override the `get_query_builder_class()` method." % self.__class__.__name__
79
+ f"'{self.__class__.__name__}' should either include a `query_builder_class` attribute, "
80
+ "or override the `get_query_builder_class()` method."
86
81
  )
87
82
  return self.query_builder_class
88
83
 
@@ -113,11 +108,9 @@ class HaystackAutocompleteFilter(HaystackFilter):
113
108
  for field_name, query in filters.children:
114
109
  for word in query.split(" "):
115
110
  bit = queryset.query.clean(word.strip())
116
- kwargs = {
117
- field_name: bit
118
- }
111
+ kwargs = {field_name: bit}
119
112
  query_bits.append(view.query_object(**kwargs))
120
- return six.moves.reduce(operator.and_, filter(lambda x: x, query_bits))
113
+ return reduce(operator.and_, filter(lambda x: x, query_bits))
121
114
 
122
115
 
123
116
  class HaystackGEOSpatialFilter(BaseHaystackFilterBackend):
@@ -154,7 +147,7 @@ class HaystackHighlightFilter(HaystackFilter):
154
147
  """
155
148
 
156
149
  def filter_queryset(self, request, queryset, view):
157
- queryset = super(HaystackHighlightFilter, self).filter_queryset(request, queryset, view)
150
+ queryset = super().filter_queryset(request, queryset, view)
158
151
  if self.get_request_filters(request) and isinstance(queryset, SearchQuerySet):
159
152
  queryset = queryset.highlight()
160
153
  return queryset
@@ -224,8 +217,10 @@ class HaystackOrderingFilter(OrderingFilter):
224
217
  Some docstring here!
225
218
  """
226
219
 
227
- def get_default_valid_fields(self, queryset, view, context={}):
228
- valid_fields = super(HaystackOrderingFilter, self).get_default_valid_fields(queryset, view, context)
220
+ def get_default_valid_fields(self, queryset, view, context=None):
221
+ if context is None:
222
+ context = {}
223
+ valid_fields = super().get_default_valid_fields(queryset, view, context)
229
224
 
230
225
  # Check if we need to support aggregate serializers
231
226
  serializer_class = view.get_serializer_class()
@@ -234,7 +229,9 @@ class HaystackOrderingFilter(OrderingFilter):
234
229
 
235
230
  return valid_fields
236
231
 
237
- def get_valid_fields(self, queryset, view, context={}):
232
+ def get_valid_fields(self, queryset, view, context=None):
233
+ if context is None:
234
+ context = {}
238
235
  valid_fields = getattr(view, "ordering_fields", self.ordering_fields)
239
236
 
240
237
  if valid_fields is None:
@@ -244,19 +241,17 @@ class HaystackOrderingFilter(OrderingFilter):
244
241
  # View explicitly allows filtering on all model fields.
245
242
  if not queryset.query.models:
246
243
  raise ImproperlyConfigured(
247
- "Cannot use %s with '__all__' as 'ordering_fields' attribute on a view "
244
+ f"Cannot use {self.__class__.__name__} with '__all__' as 'ordering_fields' attribute on a view "
248
245
  "which has no 'index_models' set. Either specify some 'ordering_fields', "
249
246
  "set the 'index_models' attribute or override the 'get_queryset' "
250
247
  "method and pass some 'index_models'."
251
- % self.__class__.__name__)
248
+ )
252
249
 
253
- model_fields = map(lambda model: [(field.name, field.verbose_name) for field in model._meta.fields],
254
- queryset.query.models)
250
+ model_fields = (
251
+ [(field.name, field.verbose_name) for field in model._meta.fields] for model in queryset.query.models
252
+ )
255
253
  valid_fields = list(set(reduce(operator.concat, model_fields)))
256
254
  else:
257
- valid_fields = [
258
- (item, item) if isinstance(item, six.string_types) else item
259
- for item in valid_fields
260
- ]
255
+ valid_fields = [(item, item) if isinstance(item, str) else item for item in valid_fields]
261
256
 
262
257
  return valid_fields
@@ -1,12 +1,5 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- from __future__ import absolute_import, unicode_literals
4
-
5
- import six
6
-
7
1
  from django.contrib.contenttypes.models import ContentType
8
2
  from django.http import Http404
9
-
10
3
  from haystack.backends import SQ
11
4
  from haystack.query import SearchQuerySet
12
5
  from rest_framework.generics import GenericAPIView
@@ -18,6 +11,7 @@ class HaystackGenericAPIView(GenericAPIView):
18
11
  """
19
12
  Base class for all haystack generic views.
20
13
  """
14
+
21
15
  # Use `index_models` to filter on which search index models we
22
16
  # should include in the search result.
23
17
  index_models = []
@@ -38,7 +32,7 @@ class HaystackGenericAPIView(GenericAPIView):
38
32
 
39
33
  filter_backends = [HaystackFilter]
40
34
 
41
- def get_queryset(self, index_models=[]):
35
+ def get_queryset(self, index_models=None):
42
36
  """
43
37
  Get the list of items for this view.
44
38
  Returns ``self.queryset`` if defined and is a ``self.object_class``
@@ -46,6 +40,8 @@ class HaystackGenericAPIView(GenericAPIView):
46
40
 
47
41
  @:param index_models: override `self.index_models`
48
42
  """
43
+ if index_models is None:
44
+ index_models = []
49
45
  if self.queryset is not None and isinstance(self.queryset, self.object_class):
50
46
  queryset = self.queryset.all()
51
47
  else:
@@ -72,19 +68,21 @@ class HaystackGenericAPIView(GenericAPIView):
72
68
  queryset = self.get_queryset()
73
69
  if "model" in self.request.query_params:
74
70
  try:
75
- app_label, model = map(six.text_type.lower, self.request.query_params["model"].split(".", 1))
71
+ app_label, model = map(str.lower, self.request.query_params["model"].split(".", 1))
76
72
  ctype = ContentType.objects.get(app_label=app_label, model=model)
77
73
  queryset = self.get_queryset(index_models=[ctype.model_class()])
78
74
  except (ValueError, ContentType.DoesNotExist):
79
- raise Http404("Could not find any models matching '%s'. Make sure to use a valid "
80
- "'app_label.model' name for the 'model' query parameter." % self.request.query_params["model"])
75
+ raise Http404(
76
+ "Could not find any models matching '{}'. Make sure to use a valid "
77
+ "'app_label.model' name for the 'model' query parameter.".format(self.request.query_params["model"])
78
+ )
81
79
 
82
80
  lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
83
81
  if lookup_url_kwarg not in self.kwargs:
84
82
  raise AttributeError(
85
- "Expected view %s to be called with a URL keyword argument "
86
- "named '%s'. Fix your URL conf, or set the `.lookup_field` "
87
- "attribute on the view correctly." % (self.__class__.__name__, lookup_url_kwarg)
83
+ f"Expected view {self.__class__.__name__} to be called with a URL keyword argument "
84
+ f"named '{lookup_url_kwarg}'. Fix your URL conf, or set the `.lookup_field` "
85
+ "attribute on the view correctly."
88
86
  )
89
87
  queryset = queryset.filter(self.query_object((self.document_uid_field, self.kwargs[lookup_url_kwarg])))
90
88
  count = queryset.count()
@@ -96,8 +94,8 @@ class HaystackGenericAPIView(GenericAPIView):
96
94
  raise Http404("No result matches the given query.")
97
95
 
98
96
  def filter_queryset(self, queryset):
99
- queryset = super(HaystackGenericAPIView, self).filter_queryset(queryset)
100
-
97
+ queryset = super().filter_queryset(queryset)
98
+
101
99
  if self.load_all:
102
100
  queryset = queryset.load_all()
103
101