initail elasticsearch
This commit is contained in:
@@ -14,11 +14,9 @@ from pathlib import Path
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
||||||
|
|
||||||
@@ -28,8 +26,7 @@ SECRET_KEY = 'django-insecure-@0apn-lk85pfw=z00x2ib$w9#rwz8%2v4i_n^^9jz-m9b+y55*
|
|||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = True
|
DEBUG = True
|
||||||
|
|
||||||
ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'https://rasadyar.net/']
|
ALLOWED_HOSTS = ['localhost', '127.0.0.1', 'https://rasadyar.net/', 'https://localhost:9200']
|
||||||
|
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
@@ -40,6 +37,8 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
|
'django_elasticsearch_dsl',
|
||||||
|
'django_elasticsearch_dsl_drf',
|
||||||
'rest_framework',
|
'rest_framework',
|
||||||
"corsheaders",
|
"corsheaders",
|
||||||
'rest_framework_simplejwt',
|
'rest_framework_simplejwt',
|
||||||
@@ -52,6 +51,7 @@ INSTALLED_APPS = [
|
|||||||
'apps.pos_machine.apps.PosMachineConfig',
|
'apps.pos_machine.apps.PosMachineConfig',
|
||||||
'apps.tag.apps.TagConfig',
|
'apps.tag.apps.TagConfig',
|
||||||
'apps.warehouse.apps.WarehouseConfig',
|
'apps.warehouse.apps.WarehouseConfig',
|
||||||
|
'apps.search.apps.SearchConfig',
|
||||||
'rest_captcha',
|
'rest_captcha',
|
||||||
'captcha',
|
'captcha',
|
||||||
]
|
]
|
||||||
@@ -85,7 +85,6 @@ TEMPLATES = [
|
|||||||
|
|
||||||
WSGI_APPLICATION = 'Rasaddam_Backend.wsgi.application'
|
WSGI_APPLICATION = 'Rasaddam_Backend.wsgi.application'
|
||||||
|
|
||||||
|
|
||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
||||||
|
|
||||||
@@ -111,6 +110,8 @@ REST_FRAMEWORK = {
|
|||||||
'rest_framework.authentication.SessionAuthentication',
|
'rest_framework.authentication.SessionAuthentication',
|
||||||
'rest_framework.authentication.BasicAuthentication',
|
'rest_framework.authentication.BasicAuthentication',
|
||||||
),
|
),
|
||||||
|
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
|
||||||
|
"PAGE_SIZE": 25
|
||||||
}
|
}
|
||||||
|
|
||||||
SIMPLE_JWT = {
|
SIMPLE_JWT = {
|
||||||
@@ -183,6 +184,17 @@ REST_CAPTCHA = {
|
|||||||
'NOISE_FUNCTION': 'apps.captcha_app.api.v1.serializers.noise_default'
|
'NOISE_FUNCTION': 'apps.captcha_app.api.v1.serializers.noise_default'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ELASTICSEARCH_DSL = {
|
||||||
|
# elastic HSA256 finger print f7d94c1da0668ba7874e5e09c3b1b91284fcdda97c361e0165401dc9375531b0 # noqa
|
||||||
|
# liara elastic password uYkiQ860vLW8DIbWpNjqtz2B # noqa
|
||||||
|
# local system password =z66+LCIebq4NQRR_+=R # noqa
|
||||||
|
"default": {
|
||||||
|
"hosts": "https://127.0.0.1:9200",
|
||||||
|
"http_auth": ("elastic", "uYkiQ860vLW8DIbWpNjqtz2B"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
@@ -201,7 +213,6 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/5.2/topics/i18n/
|
# https://docs.djangoproject.com/en/5.2/topics/i18n/
|
||||||
|
|
||||||
@@ -245,7 +256,6 @@ CORS_ALLOWED_ORIGINS = (
|
|||||||
'https://rasadyar.net'
|
'https://rasadyar.net'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||||
SECURE_SSL_REDIRECT = False
|
SECURE_SSL_REDIRECT = False
|
||||||
SESSION_COOKIE_SECURE = False
|
SESSION_COOKIE_SECURE = False
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ from rest_framework_simplejwt.views import TokenObtainPairView
|
|||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from apps.authentication.models import User
|
from apps.authentication.models import User
|
||||||
|
from rest_framework.views import APIView
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
|
|
||||||
|
|
||||||
@@ -28,3 +29,7 @@ class Authentication(ModelViewSet):
|
|||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def login(self, request):
|
def login(self, request):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class UserViewSet(ModelViewSet):
|
||||||
|
pass
|
||||||
53
apps/authentication/api/v1/search_view.py
Normal file
53
apps/authentication/api/v1/search_view.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
from apps.authentication.api.v1.serializers.serializer import UserSerializer
|
||||||
|
from rest_framework.pagination import LimitOffsetPagination
|
||||||
|
from rest_framework.viewsets import ModelViewSet, ViewSet
|
||||||
|
from apps.authentication.documents import UserDocument
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from django.http.response import HttpResponse
|
||||||
|
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 SearchUsersApiView(PaginatedElasticSearchApiView): # noqa
|
||||||
|
"""Search in Users"""
|
||||||
|
|
||||||
|
serializer_class = UserSerializer
|
||||||
|
document_class = UserDocument
|
||||||
|
|
||||||
|
def generate_q_expression(self, query):
|
||||||
|
return Q(
|
||||||
|
'multi_match',
|
||||||
|
query=query,
|
||||||
|
fields=[
|
||||||
|
'username',
|
||||||
|
'mobile'
|
||||||
|
], fuzziness='auto'
|
||||||
|
)
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
from rest_framework import serializers
|
||||||
|
from apps.authentication.models import User
|
||||||
|
|
||||||
|
|
||||||
|
class UserSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = User
|
||||||
|
fields = [
|
||||||
|
'username',
|
||||||
|
'mobile'
|
||||||
|
]
|
||||||
|
|||||||
@@ -5,10 +5,14 @@ from rest_framework_simplejwt.views import (
|
|||||||
TokenRefreshView,
|
TokenRefreshView,
|
||||||
TokenVerifyView
|
TokenVerifyView
|
||||||
)
|
)
|
||||||
from .api import CustomizedTokenObtainPairView
|
from .api import (
|
||||||
|
CustomizedTokenObtainPairView
|
||||||
|
)
|
||||||
|
from .search_view import SearchUsersApiView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('login/', CustomizedTokenObtainPairView.as_view(), name='token_obtain_pair'),
|
path('login/', CustomizedTokenObtainPairView.as_view(), name='token_obtain_pair'),
|
||||||
|
path('search_user/<str:query>', SearchUsersApiView.as_view(), name='search_user'),
|
||||||
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
|
||||||
path('token/verify/', TokenVerifyView.as_view(), name='token_verify'),
|
path('token/verify/', TokenVerifyView.as_view(), name='token_verify'),
|
||||||
]
|
]
|
||||||
|
|||||||
24
apps/authentication/documents.py
Normal file
24
apps/authentication/documents.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
from .models import User, Province
|
||||||
|
from django_elasticsearch_dsl import Document, fields
|
||||||
|
from django_elasticsearch_dsl.registries import registry
|
||||||
|
|
||||||
|
|
||||||
|
@registry.register_document
|
||||||
|
class UserDocument(Document):
|
||||||
|
"""ElasticSearch Document for indexing users"""
|
||||||
|
|
||||||
|
class Index:
|
||||||
|
name = 'users'
|
||||||
|
settings = {
|
||||||
|
'number_of_shards': 1,
|
||||||
|
'number_of_replicas': 0 # number of copies from data in document
|
||||||
|
}
|
||||||
|
|
||||||
|
class Django:
|
||||||
|
model = User
|
||||||
|
fields = [
|
||||||
|
"id",
|
||||||
|
"username",
|
||||||
|
"mobile",
|
||||||
|
"nationality"
|
||||||
|
]
|
||||||
@@ -1,3 +1 @@
|
|||||||
from django.shortcuts import render
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|||||||
0
apps/search/__init__.py
Normal file
0
apps/search/__init__.py
Normal file
3
apps/search/admin.py
Normal file
3
apps/search/admin.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.contrib import admin
|
||||||
|
|
||||||
|
# Register your models here.
|
||||||
6
apps/search/apps.py
Normal file
6
apps/search/apps.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class SearchConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'apps.search'
|
||||||
BIN
apps/search/certs/http.p12
Normal file
BIN
apps/search/certs/http.p12
Normal file
Binary file not shown.
31
apps/search/certs/http_ca.crt
Normal file
31
apps/search/certs/http_ca.crt
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
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
|
||||||
|
-----END CERTIFICATE-----
|
||||||
BIN
apps/search/certs/transport.p12
Normal file
BIN
apps/search/certs/transport.p12
Normal file
Binary file not shown.
3
apps/search/models.py
Normal file
3
apps/search/models.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
# Create your models here.
|
||||||
3
apps/search/tests.py
Normal file
3
apps/search/tests.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
4
apps/search/views.py
Normal file
4
apps/search/views.py
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
from elasticsearch_dsl import Q
|
||||||
|
from apps.authentication.models import User
|
||||||
|
from apps.authentication.documents import UserDocument
|
||||||
@@ -13,6 +13,12 @@ class Tag(BaseModel):
|
|||||||
related_name="tag_province",
|
related_name="tag_province",
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
|
city = models.ForeignKey(
|
||||||
|
auth_models.City,
|
||||||
|
on_delete=models.CASCADE,
|
||||||
|
related_name='tag_city',
|
||||||
|
null=True
|
||||||
|
)
|
||||||
organization = models.ForeignKey(
|
organization = models.ForeignKey(
|
||||||
auth_models.Organization,
|
auth_models.Organization,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
|
|||||||
@@ -66,4 +66,8 @@ XlsxWriter
|
|||||||
zipp
|
zipp
|
||||||
django-simple-captcha
|
django-simple-captcha
|
||||||
django-rest-captcha
|
django-rest-captcha
|
||||||
pymemcache
|
pymemcache
|
||||||
|
elasticsearch==8.11.0
|
||||||
|
elasticsearch-dsl==8.11.0
|
||||||
|
django-elasticsearch-dsl==8.0
|
||||||
|
django_elasticsearch_dsl_drf
|
||||||
Reference in New Issue
Block a user