Skip to content

Commit 3574909

Browse files
authored
Merge pull request #80 from django-oscar/add_lookup_term_query
Add lookup term query
2 parents 8a4bcb4 + 69641d3 commit 3574909

File tree

15 files changed

+282
-1
lines changed

15 files changed

+282
-1
lines changed

oscar_elasticsearch/search/api/base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,6 @@ def get_index_settings(self):
1515

1616
def get_model(self):
1717
return self.Model
18+
19+
def get_queryset(self):
20+
return self.Model.objects.all()
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from oscar.core.loading import get_class
2+
3+
BaseElasticSearchApi = get_class("search.api.search", "BaseElasticSearchApi")
4+
ESModelIndexer = get_class("search.indexing.indexer", "ESModelIndexer")
5+
6+
7+
class BaseLookupIndex(BaseElasticSearchApi, ESModelIndexer):
8+
"""
9+
Subclass this class to create a custom lookup for your index.
10+
https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-terms-query.html#query-dsl-terms-lookup
11+
12+
set LOOKUP_PATH as the field you want to save on the lookup index, that you can use to filter stuff on the main index you're using
13+
14+
Example for make_documents:
15+
def make_documents(self, objects):
16+
documents = []
17+
18+
for user in objects:
19+
documents.append([
20+
{
21+
"_id": user.id,
22+
self.LOOKUP_PATH: [p.id, for p in user.products]
23+
}
24+
]
25+
)
26+
27+
return documents
28+
29+
"""
30+
31+
LOOKUP_PATH = None
32+
INDEX_SETTINGS = {}
33+
34+
def get_index_mapping(self):
35+
if self.LOOKUP_PATH is None:
36+
raise NotImplementedError("Please set LOOKUP_PATH on your lookup index")
37+
38+
return {"properties": {self.LOOKUP_PATH: {"type": "keyword"}}}
39+
40+
def get_lookup_id(self, field_to_filter, **kwargs):
41+
raise NotImplementedError(
42+
"""
43+
Please implement 'get_lookup_id' on your lookup index.
44+
Return None to not apply this lookup filter, return the actual id to filter on that id,
45+
Id's should always be strings (elasticsearch), never integers
46+
"""
47+
)
48+
49+
def get_lookup_query(self, field_to_filter, **kwargs):
50+
lookup_id = self.get_lookup_id(field_to_filter, **kwargs)
51+
52+
if lookup_id is not None:
53+
return {
54+
"terms": {
55+
field_to_filter: {
56+
"index": self.get_index_name(),
57+
"id": lookup_id,
58+
"path": self.LOOKUP_PATH,
59+
}
60+
}
61+
}
62+
63+
return None
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
from oscar_elasticsearch.search.registry import elasticsearch_registry
2+
from django.core.management.base import BaseCommand
3+
4+
from oscar.core.loading import get_class
5+
6+
from oscar_elasticsearch.search import settings
7+
8+
chunked = get_class("search.utils", "chunked")
9+
10+
11+
class Command(BaseCommand):
12+
def handle(self, *args, **options):
13+
for Index in elasticsearch_registry.indexes:
14+
index = Index()
15+
16+
self.stdout.write(
17+
self.style.SUCCESS(
18+
"\n Start indexing index: %s" % index.get_index_name()
19+
)
20+
)
21+
22+
index_queryset = index.get_queryset()
23+
with index.reindex() as index:
24+
for chunk in chunked(index_queryset, settings.INDEXING_CHUNK_SIZE):
25+
index.reindex_objects(chunk)
26+
self.stdout.write(".", ending="")
27+
self.stdout.flush() # Ensure the dots are displayed immediately
28+
29+
self.stdout.write(
30+
self.style.SUCCESS(
31+
"\n%i %s successfully indexed"
32+
% (index_queryset.count(), index.get_index_name())
33+
)
34+
)

oscar_elasticsearch/search/management/commands/update_oscar_index.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ class Command(BaseCommand):
66
def handle(self, *args, **options):
77
call_command("update_index_products")
88
call_command("update_index_categories")
9+
call_command("update_index_registered")
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class ElasticsearchRegistry:
2+
_indexes = []
3+
4+
def register(self, cls):
5+
self._indexes.append(cls)
6+
return cls
7+
8+
@property
9+
def indexes(self):
10+
return self._indexes
11+
12+
13+
elasticsearch_registry = ElasticsearchRegistry()

pylintrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ load-plugins=pylint_django
44
score=n
55
ignore = migrations
66
django-settings-module = sandbox.settings
7+
init-hook='import sys; sys.path.append("./sandbox/")'
78

89
[MESSAGES CONTROL]
910
disable=R,C

sandbox/__init__.py

Whitespace-only changes.

sandbox/assortment/__init__.py

Whitespace-only changes.

sandbox/assortment/admin.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from django.contrib import admin
2+
3+
from .models import AssortmentProduct, AssortmentUser
4+
5+
6+
class AssortmentProductAdmin(admin.TabularInline):
7+
model = AssortmentProduct
8+
list_display = search_fields = ["product"]
9+
10+
11+
class AssortmentUserAdmin(admin.ModelAdmin):
12+
list_display = search_fields = ["user"]
13+
inlines = [
14+
AssortmentProductAdmin
15+
]
16+
17+
18+
admin.site.register(AssortmentUser, AssortmentUserAdmin)

sandbox/assortment/apps.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from django.apps import AppConfig
2+
3+
4+
class AssortmentConfig(AppConfig):
5+
name = "assortment"
6+
verbose_name = "Assortment"
7+
8+
def ready(self):
9+
from . import index

0 commit comments

Comments
 (0)