first base of project-changed apps: Herd-livestock-tag-log-elasticsearch-
This commit is contained in:
0
apps/search/api/__init__.py
Normal file
0
apps/search/api/__init__.py
Normal file
0
apps/search/api/v1/__init__.py
Normal file
0
apps/search/api/v1/__init__.py
Normal file
61
apps/search/api/v1/api.py
Normal file
61
apps/search/api/v1/api.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from .serializers import UserRelationDocumentSerializer
|
||||
from django_elasticsearch_dsl_drf.viewsets import DocumentViewSet
|
||||
from rest_framework.pagination import LimitOffsetPagination
|
||||
from apps.search.document.user_document import UserRelationDocument
|
||||
from django.http.response import HttpResponse
|
||||
from rest_framework.response import Response
|
||||
from apps.authentication.models import User
|
||||
from rest_framework.views import APIView
|
||||
from elasticsearch_dsl.query import Q
|
||||
import abc
|
||||
|
||||
|
||||
class PaginatedElasticSearchApiView(APIView, LimitOffsetPagination):
|
||||
"""Base ApiView Class for elasticsearch views with pagination,
|
||||
Other ApiView classes should inherit from this class"""
|
||||
serializer_class = None
|
||||
document_class = None
|
||||
|
||||
@abc.abstractmethod
|
||||
def generate_q_expression(self, query):
|
||||
"""This method should be overridden
|
||||
and return a Q() expression."""
|
||||
|
||||
def get(self, request, query):
|
||||
try:
|
||||
q = self.generate_q_expression(query)
|
||||
search = self.document_class.search().query(q)
|
||||
response = search.execute()
|
||||
|
||||
print(f"Found {response.hits.total.value} hit(s) for query: '{query}'")
|
||||
|
||||
results = self.paginate_queryset(response, request, view=self) # noqa
|
||||
serializer = self.serializer_class(results, many=True)
|
||||
return self.get_paginated_response(serializer.data)
|
||||
except Exception as e:
|
||||
return HttpResponse(e, status=500)
|
||||
|
||||
|
||||
class SearchUserDocumentApiView(PaginatedElasticSearchApiView):
|
||||
"""Base ApiView Class for elasticsearch views with pagination,
|
||||
Other ApiView classes should inherit from this class"""
|
||||
serializer_class = UserRelationDocumentSerializer
|
||||
document_class = UserRelationDocument
|
||||
|
||||
def generate_q_expression(self, query):
|
||||
return Q(
|
||||
'bool',
|
||||
should=[
|
||||
Q("match", user__username=query),
|
||||
Q("match", user__mobile=query),
|
||||
Q("match", user__national_code=query),
|
||||
Q("match", organization__type__key=query),
|
||||
Q("match", organization__name=query),
|
||||
Q("match", organization__city__name=query),
|
||||
Q("match", organization__province__name=query),
|
||||
Q("match", organization__national_unique_id=query),
|
||||
Q("match", organization__company_code=query),
|
||||
Q("match", role__role_name=query),
|
||||
],
|
||||
minimum_should_match=1,
|
||||
)
|
||||
15
apps/search/api/v1/serializers.py
Normal file
15
apps/search/api/v1/serializers.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from django_elasticsearch_dsl_drf.serializers import DocumentSerializer
|
||||
from apps.search.documents import UserRelationDocument
|
||||
|
||||
|
||||
class UserRelationDocumentSerializer(DocumentSerializer):
|
||||
"""Serializer for user relation document."""
|
||||
|
||||
class Meta:
|
||||
document = UserRelationDocument
|
||||
fields = (
|
||||
'id',
|
||||
'user',
|
||||
'organization',
|
||||
'role'
|
||||
)
|
||||
10
apps/search/api/v1/urls.py
Normal file
10
apps/search/api/v1/urls.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.urls import path, include
|
||||
from .api import SearchUserDocumentApiView
|
||||
from rest_framework import routers
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
|
||||
urlpatterns = [
|
||||
path('', include(router.urls), name='search_user'),
|
||||
path('user_elastic/<str:query>/', SearchUserDocumentApiView.as_view()),
|
||||
]
|
||||
0
apps/search/api/v1/views.py
Normal file
0
apps/search/api/v1/views.py
Normal file
0
apps/search/api/v2/__init__.py
Normal file
0
apps/search/api/v2/__init__.py
Normal file
0
apps/search/api/v2/serializers.py
Normal file
0
apps/search/api/v2/serializers.py
Normal file
0
apps/search/api/v2/urls.py
Normal file
0
apps/search/api/v2/urls.py
Normal file
0
apps/search/api/v2/views.py
Normal file
0
apps/search/api/v2/views.py
Normal file
Binary file not shown.
@@ -1,31 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
Binary file not shown.
154
apps/search/document/user_document.py
Normal file
154
apps/search/document/user_document.py
Normal file
@@ -0,0 +1,154 @@
|
||||
from django_elasticsearch_dsl_drf.compat import StringField, KeywordField
|
||||
from elasticsearch_dsl import analyzer
|
||||
from apps.authorization.models import UserRelations, Role
|
||||
from apps.authentication.models import User, Organization
|
||||
from django_elasticsearch_dsl.registries import registry
|
||||
from django_elasticsearch_dsl import Document, fields
|
||||
|
||||
html_strip = analyzer(
|
||||
'html_strip',
|
||||
tokenizer="standard",
|
||||
filter=["lowercase", "stop", "snowball"],
|
||||
char_filter=["html_strip"]
|
||||
)
|
||||
|
||||
|
||||
@registry.register_document
|
||||
class UserRelationDocument(Document):
|
||||
"""Address Elasticsearch document."""
|
||||
|
||||
# In different parts of the code different fields are used. There are
|
||||
# a couple of use cases: (1) more-like-this functionality, where `title`,
|
||||
# `description` and `summary` fields are used, (2) search and filtering
|
||||
# functionality where all the fields are used.
|
||||
|
||||
user = fields.ObjectField(properties={
|
||||
'username': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
'mobile': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': KeywordField()
|
||||
}
|
||||
),
|
||||
'national_code': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
'first_name': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
'last_name': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
})
|
||||
organization = fields.ObjectField(properties={
|
||||
'name': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
'type': fields.ObjectField(properties={
|
||||
'key': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
)
|
||||
}),
|
||||
'national_unique_id': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
'field_of_activity': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
'company_code': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
'province': fields.ObjectField(properties={
|
||||
'name': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
}),
|
||||
'city': fields.ObjectField(properties={
|
||||
'name': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
}),
|
||||
'parent_organization': fields.ObjectField(properties={
|
||||
'name': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
'unique_national_id': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
),
|
||||
})
|
||||
})
|
||||
role = fields.ObjectField(properties={
|
||||
'role_name': StringField(
|
||||
analyzer=html_strip,
|
||||
fields={
|
||||
'raw': KeywordField(),
|
||||
'suggest': fields.CompletionField()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
class Index:
|
||||
name = 'userrelations' # noqa
|
||||
settings = {
|
||||
'number_of_shards': 1,
|
||||
'number_of_replicas': 1 # number of copies from data in document
|
||||
}
|
||||
|
||||
class Django:
|
||||
model = UserRelations
|
||||
relates_models = [User, Organization, Role]
|
||||
1
apps/search/documents.py
Normal file
1
apps/search/documents.py
Normal file
@@ -0,0 +1 @@
|
||||
from apps.search.document.user_document import UserRelationDocument
|
||||
0
apps/search/fixtures/.gitkeep
Normal file
0
apps/search/fixtures/.gitkeep
Normal file
0
apps/search/management/__init__.py
Normal file
0
apps/search/management/__init__.py
Normal file
0
apps/search/management/commands/__init__.py
Normal file
0
apps/search/management/commands/__init__.py
Normal file
1
apps/search/management/commands/command.py
Normal file
1
apps/search/management/commands/command.py
Normal file
@@ -0,0 +1 @@
|
||||
# Your custom management commands go here.
|
||||
71
apps/search/signals.py
Normal file
71
apps/search/signals.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from django.db.models.signals import post_save, post_delete
|
||||
from django.dispatch import receiver
|
||||
|
||||
from django_elasticsearch_dsl.registries import registry
|
||||
|
||||
|
||||
@receiver(post_save)
|
||||
def update_document(sender, **kwargs):
|
||||
"""Update document on added/changed records.
|
||||
|
||||
Update Book document index if related `books.Publisher` (`publisher`),
|
||||
`books.Author` (`authors`), `books.Tag` (`tags`) fields have been updated
|
||||
in the database.
|
||||
"""
|
||||
app_label = sender._meta.app_label
|
||||
model_name = sender._meta.model_name
|
||||
instance = kwargs['instance']
|
||||
|
||||
if app_label == 'book':
|
||||
# If it is `books.Publisher` that is being updated.
|
||||
if model_name == 'publisher':
|
||||
instances = instance.books.all()
|
||||
for _instance in instances:
|
||||
registry.update(_instance)
|
||||
|
||||
# If it is `books.Author` that is being updated.
|
||||
if model_name == 'author':
|
||||
instances = instance.books.all()
|
||||
for _instance in instances:
|
||||
registry.update(_instance)
|
||||
|
||||
# If it is `books.Tag` that is being updated.
|
||||
if model_name == 'tag':
|
||||
instances = instance.books.all()
|
||||
for _instance in instances:
|
||||
registry.update(_instance)
|
||||
|
||||
|
||||
@receiver(post_delete)
|
||||
def delete_document(sender, **kwargs):
|
||||
"""Update document on deleted records.
|
||||
|
||||
Updates Book document from index if related `books.Publisher`
|
||||
(`publisher`), `books.Author` (`authors`), `books.Tag` (`tags`) fields
|
||||
have been removed from database.
|
||||
"""
|
||||
app_label = sender._meta.app_label
|
||||
model_name = sender._meta.model_name
|
||||
instance = kwargs['instance']
|
||||
|
||||
if app_label == 'books':
|
||||
# If it is `books.Publisher` that is being updated.
|
||||
if model_name == 'publisher':
|
||||
instances = instance.books.all()
|
||||
for _instance in instances:
|
||||
registry.update(_instance)
|
||||
# registry.delete(_instance, raise_on_error=False)
|
||||
|
||||
# If it is `books.Author` that is being updated.
|
||||
if model_name == 'author':
|
||||
instances = instance.books.all()
|
||||
for _instance in instances:
|
||||
registry.update(_instance)
|
||||
# registry.delete(_instance, raise_on_error=False)
|
||||
|
||||
# If it is `books.Tag` that is being updated.
|
||||
if model_name == 'tag':
|
||||
instances = instance.books.all()
|
||||
for _instance in instances:
|
||||
registry.update(_instance)
|
||||
# registry.delete(_instance, raise_on_error=False)
|
||||
0
apps/search/tests/test_common_services.py
Normal file
0
apps/search/tests/test_common_services.py
Normal file
5
apps/search/urls.py
Normal file
5
apps/search/urls.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from django.urls import path, include
|
||||
|
||||
urlpatterns = [
|
||||
path('api/v1/', include('apps.search.api.v1.urls'))
|
||||
]
|
||||
Reference in New Issue
Block a user