탄력적 검색 + 장고
15804 단어 haystackdjangopythonelasticsearch
요구 사항:
프로젝트 설정:
$ mkdir dj_elastic && cd dj_elastic
$ python3 -m venv env
$ source env/bin/activate
$ poetry init
$ poetry add django djangorestframework django-autoslug black isort
$ poetry add django-haystack drf-haystack
$ poetry add elasticsearch==^7.x.x
$ django-admin.py startproject main
$ python manage.py startapp searches
$ python manage.py startapp commons
프로젝트 디렉토리는 다음과 같아야 합니다.
── dj_elastic
├── main
│ ├── **init**.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
└── commons
└── searches
기본 앱/url.py
from django.contrib import admin
from django.urls import path
from django.urls.conf import include
urlpatterns = [
path("admin/", admin.site.urls),
path("api/v1/", include("searches.urls")),
]
메인/settings.py
INSTALLED_APPS = [
"searches",
"commons",
"haystack",
"rest_framework",
]
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
HAYSTACK_CONNECTIONS = {
"default": {
'ENGINE': 'haystack.backends.elasticsearch7_backend.Elasticsearch7SearchEngine',
"URL": "http://127.0.0.1:9200/",
"INDEX_NAME": "haystack",
},
}
HAYSTACK_SIGNAL_PROCESSOR = "haystack.signals.RealtimeSignalProcessor"
👏🏻 좋아요 기본셋팅 끝....
다음으로 모델을 생성해 보겠습니다. commons/models.py로 이동합니다.
# commons/models.py
from django.db import models
from autoslug import AutoSlugField
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
def slugify(value):
return value.replace(" ", "-").lower()
class ConfigChoiceCategory(models.Model):
name = models.CharField(
_("Config Choice Category Name"),
help_text=_("Required and Unique"),
max_length=255,
unique=True,
)
slug = AutoSlugField(
verbose_name=_("Config Choice Category Slug"),
populate_from="name",
slugify=slugify,
)
entered_by = models.ForeignKey(User, blank=True, on_delete=models.CASCADE)
is_active = models.BooleanField(default=True)
class Meta:
verbose_name = _("Config Choice Category")
verbose_name_plural = _(" Config Choice Categories")
def __str__(self):
return self.name
class ConfigChoice(models.Model):
name = models.CharField(
_("Config Choice Name"),
help_text=_("Required and Unique"),
max_length=255,
unique=True,
)
description = models.TextField()
slug = AutoSlugField(
verbose_name=_("Config Choice Slug"),
populate_from="name",
slugify=slugify,
)
config_choice_category = models.ForeignKey(
ConfigChoiceCategory, on_delete=models.CASCADE
)
entered_by = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name = _("Config Choice")
verbose_name_plural = _("Config Choices")
def __str__(self) -> str:
return self.name
class Address(models.Model):
street_1 = models.CharField(max_length=200)
street_2 = models.CharField(max_length=200, null=True, blank=True)
city = models.CharField(max_length=100)
state = models.CharField(max_length=100)
zip_code = models.CharField(max_length=100)
country = models.CharField(max_length=50)
latitude = models.FloatField()
longitude = models.FloatField()
def __str__(self):
return f"{self.street_1}, {self.city}, {self.state}, {self.country}"``
여기서 우리는:
$ mkdir dj_elastic && cd dj_elastic
$ python3 -m venv env
$ source env/bin/activate
$ poetry init
$ poetry add django djangorestframework django-autoslug black isort
$ poetry add django-haystack drf-haystack
$ poetry add elasticsearch==^7.x.x
$ django-admin.py startproject main
$ python manage.py startapp searches
$ python manage.py startapp commons
── dj_elastic
├── main
│ ├── **init**.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
└── commons
└── searches
from django.contrib import admin
from django.urls import path
from django.urls.conf import include
urlpatterns = [
path("admin/", admin.site.urls),
path("api/v1/", include("searches.urls")),
]
INSTALLED_APPS = [
"searches",
"commons",
"haystack",
"rest_framework",
]
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
HAYSTACK_CONNECTIONS = {
"default": {
'ENGINE': 'haystack.backends.elasticsearch7_backend.Elasticsearch7SearchEngine',
"URL": "http://127.0.0.1:9200/",
"INDEX_NAME": "haystack",
},
}
HAYSTACK_SIGNAL_PROCESSOR = "haystack.signals.RealtimeSignalProcessor"
# commons/models.py
from django.db import models
from autoslug import AutoSlugField
from django.contrib.auth.models import User
from django.utils.translation import gettext_lazy as _
def slugify(value):
return value.replace(" ", "-").lower()
class ConfigChoiceCategory(models.Model):
name = models.CharField(
_("Config Choice Category Name"),
help_text=_("Required and Unique"),
max_length=255,
unique=True,
)
slug = AutoSlugField(
verbose_name=_("Config Choice Category Slug"),
populate_from="name",
slugify=slugify,
)
entered_by = models.ForeignKey(User, blank=True, on_delete=models.CASCADE)
is_active = models.BooleanField(default=True)
class Meta:
verbose_name = _("Config Choice Category")
verbose_name_plural = _(" Config Choice Categories")
def __str__(self):
return self.name
class ConfigChoice(models.Model):
name = models.CharField(
_("Config Choice Name"),
help_text=_("Required and Unique"),
max_length=255,
unique=True,
)
description = models.TextField()
slug = AutoSlugField(
verbose_name=_("Config Choice Slug"),
populate_from="name",
slugify=slugify,
)
config_choice_category = models.ForeignKey(
ConfigChoiceCategory, on_delete=models.CASCADE
)
entered_by = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name = _("Config Choice")
verbose_name_plural = _("Config Choices")
def __str__(self) -> str:
return self.name
class Address(models.Model):
street_1 = models.CharField(max_length=200)
street_2 = models.CharField(max_length=200, null=True, blank=True)
city = models.CharField(max_length=100)
state = models.CharField(max_length=100)
zip_code = models.CharField(max_length=100)
country = models.CharField(max_length=50)
latitude = models.FloatField()
longitude = models.FloatField()
def __str__(self):
return f"{self.street_1}, {self.city}, {self.state}, {self.country}"``
admin.py에 모델 등록
from django.contrib import admin
# Register your models here.
from .models import (
Address,
ConfigChoice,
ConfigChoiceCategory,
)
admin.site.register(ConfigChoiceCategory)
admin.site.register(ConfigChoice)
admin.site.register(Address)
이제 검색 앱으로 이동하여 호텔용 모델을 생성해 보겠습니다.
#searches/models.py
from commons.models import Address, ConfigChoice
from django.db import models
from django.utils.translation import gettext_lazy as _
from autoslug import AutoSlugField
def slugify(value):
return value.replace(" ", "-").lower()
class CoreModel(models.Model):
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class HotelType(models.Model):
name = models.CharField(_("Hotel Types Name"), max_length=255)
class Meta:
verbose_name = _("Hotel Type")
verbose_name_plural = _("Hotel Types")
def __str__(self) -> str:
return self.name
class HotelSpecifications(models.Model):
hotel_type = models.ForeignKey(HotelType, on_delete=models.RESTRICT)
name = models.CharField(_("Hotel Spec Name"), max_length=255)
class Meta:
verbose_name = _("Hotel Specification")
verbose_name_plural = _("Hotel Specifications")
def __str__(self) -> str:
return f"{self.name}"
class Hotel(CoreModel):
name = models.CharField(_("Hotel Name"), max_length=50)
description = models.TextField(_("Hotel Descriptions"), default="")
hotel_type = models.ForeignKey(HotelType, on_delete=models.CASCADE)
slug = AutoSlugField(
verbose_name=_("Hotel Slug"),
populate_from="name",
slugify=slugify,
)
is_active = models.BooleanField(default=True)
config_choice = models.ForeignKey(ConfigChoice, on_delete=models.RESTRICT)
class Meta:
verbose_name = _("Hotel")
verbose_name_plural = _("Hotels")
def get_absolute_url(self):
return f"/{self.slug}/"
def __str__(self) -> str:
return self.name
class HotelSpecificationValue(models.Model):
hotel = models.ForeignKey(Hotel, on_delete=models.CASCADE)
specification = models.ForeignKey(HotelSpecifications, on_delete=models.RESTRICT)
value = models.CharField(
_("Value"),
max_length=255,
help_text=_("Hotel specification value (maximum of 255 words"),
)
class Meta:
verbose_name = _("Hotel Specification Value")
verbose_name_plural = _("Hotel Specification Values")
def __str__(self):
return self.value
class HotelImage(CoreModel):
hotel = models.ForeignKey(
Hotel, on_delete=models.CASCADE, related_name="hotel_image"
)
image_urls = models.URLField(
_("Hotel Image URLs"),
help_text=_("Images Urls"),
)
caption = models.CharField(
verbose_name=_("Alternative text"),
help_text=_("Please add alturnative text"),
max_length=255,
null=True,
blank=True,
)
is_feature = models.BooleanField(default=False)
class Meta:
verbose_name = _("Hotel Image")
verbose_name_plural = _("Hotel Images")
class HotelAddress(models.Model):
hotel = models.ForeignKey(
Hotel, on_delete=models.CASCADE, related_name="hotel_address"
)
address = models.ForeignKey(Address, on_delete=models.CASCADE)
def __str__(self):
return f"{self.hotel.name} {self.address.city}"
admin.py에 모델 등록
from django.contrib import admin
from .models import (
Hotel,
HotelImage,
HotelSpecifications,
HotelSpecificationValue,
HotelType,
HotelAddress,
)
class HotelSpecificationInline(admin.TabularInline):
model = HotelSpecifications
@admin.register(HotelType)
class HotelTypeAdmin(admin.ModelAdmin):
inlines = [
HotelSpecificationInline,
]
class HotelImageInline(admin.TabularInline):
model = HotelImage
class HotelSpecificationValueInline(admin.TabularInline):
model = HotelSpecificationValue
@admin.register(Hotel)
class HotelAdmin(admin.ModelAdmin):
inlines = [HotelSpecificationValueInline, HotelImageInline]
admin.site.register(HotelAddress)
검색 앱 내에 search_indexes.py 파일을 만듭니다.
#searches/search_indexes.py
from django.utils import timezone
from haystack import indexes
from .models import Hotel, HotelAddress, HotelImage, HotelSpecificationValue
class HotelIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
name = indexes.CharField(model_attr="name")
hotel_type = indexes.CharField(model_attr="hotel_type")
config_choice = indexes.CharField(model_attr="config_choice")
autocomplete = indexes.EdgeNgramField()
@staticmethod
def prepare_autocomplete(obj):
return " ".join((obj.name, obj.hotel_type.name, obj.config_choice.name))
def get_model(self):
return Hotel
class HotelSpecIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
value = indexes.CharField(model_attr="value")
def get_model(self):
return HotelSpecificationValue
class HotelImageIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
image_urls = indexes.CharField(model_attr="image_urls")
caption = indexes.CharField(model_attr="caption")
def get_model(self):
return HotelImage
class HotelAddressIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
address = indexes.CharField(model_attr="address")
def get_model(self):
return HotelAddress
직렬화 및 보기:
#searches/serializers.py
from drf_haystack.serializers import HaystackSerializer
from .search_indexes import (
HotelIndex,
HotelSpecIndex,
HotelImageIndex,
HotelAddressIndex,
)
class AggregateSerializer(HaystackSerializer):
class Meta:
index_classes = [HotelIndex, HotelSpecIndex, HotelImageIndex, HotelAddressIndex]
fields = [
"name",
"hotel",
"config_choice",
"value",
"image_urls",
"caption",
"address",
"autocomplete",
]
# searches/serializers.py
from .serializers import AggregateSerializer
from rest_framework.mixins import ListModelMixin
from drf_haystack.generics import HaystackGenericAPIView
class AggregateSearchViewSet(ListModelMixin, HaystackGenericAPIView):
serializer_class = AggregateSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
so you can create a each class of serializers for each models Like this.
# searches/urls.py
from django.urls import path
from .views import AggregateSearchViewSet
urlpatterns = [
path("hotels/search/", AggregateSearchViewSet.as_view())
]
검색 앱 내에 템플릿 디렉토리를 만듭니다.
템플릿 폴더는 다음과 같습니다.
templates
├── search
├── indexes
├── searches
├── hotel_text.txt
├── hoteladdress_text.txt
├── hotelimage_text.txt
├── hotelspecificationvalue_text.txt
마지막으로 앱을 마이그레이션하고 수퍼유저를 생성하고 django 관리 패널을 사용하여 일부 호텔 데이터를 추가합니다.
간단히 실행
./manage.py rebuild_index.
처리되어 인덱스에 배치된 모델 수에 대한 총계를 얻을 수 있습니다.
쿼리 시간!
이제 보기가 연결되었으므로 사용을 시작할 수 있습니다. 기본적으로 HaystackGenericAPIView 클래스는 HaystackFilter를 사용하도록 설정됩니다. 이것은 포함된 가장 기본적인 필터이며 직렬 변환기의 필드 속성에 포함된 필드를 쿼리하여 기본 검색을 수행할 수 있습니다.
http://127.0.0.1:8000/api/v1/hotels/search/
[
{
"image_urls": "https://images.moviesanywhere.com/8ccb2868a61ac0612d780eb3b18e5220/6fda2dc9-a774-4ba6-9e80-679accfcc8ed.jpg?h=375&resize=fit&w=250",
"caption": "img"
},
{
"name": "Transylvania Hotal",
"config_choice": "Active",
"autocomplete": "Transylvania Hotal 3 Star Active"
},
{
"value": "12 AD"
},
{
"value": "Monsters Hotel"
},
{
"address": "US"
},
{
"value": "12 AD"
},
{
"value": "gogogog"
},
{
"image_urls": "https://images.moviesanywhere.com/8ccb2868a61ac0612d780eb3b18e5220/6fda2dc9-a774-4ba6-9e80-679accfcc8ed.jpg?h=375&resize=fit&w=250",
"caption": "img"
},
{
"value": "lONG LONG TIME AGO"
},
{
"name": "demo",
"config_choice": "Active",
"autocomplete": "demo 3 Star Active"
},
{
"value": "lONG LONG TIME AGO"
}
]
http://127.0.0.1:8000/api/v1/hotels/search/?name="demo"
"results": [
{
"name": "demo",
"config_choice": "Active",
"autocomplete": "demo 3 Star Active"
}
]
리야마
/
elastic_search_dj_예제
Django + haystack + 탄력적 검색의 예
Reference
이 문제에 관하여(탄력적 검색 + 장고), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/lyamaa/elastic-search-django-g85
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
http://127.0.0.1:8000/api/v1/hotels/search/
[
{
"image_urls": "https://images.moviesanywhere.com/8ccb2868a61ac0612d780eb3b18e5220/6fda2dc9-a774-4ba6-9e80-679accfcc8ed.jpg?h=375&resize=fit&w=250",
"caption": "img"
},
{
"name": "Transylvania Hotal",
"config_choice": "Active",
"autocomplete": "Transylvania Hotal 3 Star Active"
},
{
"value": "12 AD"
},
{
"value": "Monsters Hotel"
},
{
"address": "US"
},
{
"value": "12 AD"
},
{
"value": "gogogog"
},
{
"image_urls": "https://images.moviesanywhere.com/8ccb2868a61ac0612d780eb3b18e5220/6fda2dc9-a774-4ba6-9e80-679accfcc8ed.jpg?h=375&resize=fit&w=250",
"caption": "img"
},
{
"value": "lONG LONG TIME AGO"
},
{
"name": "demo",
"config_choice": "Active",
"autocomplete": "demo 3 Star Active"
},
{
"value": "lONG LONG TIME AGO"
}
]
http://127.0.0.1:8000/api/v1/hotels/search/?name="demo"
"results": [
{
"name": "demo",
"config_choice": "Active",
"autocomplete": "demo 3 Star Active"
}
]
Reference
이 문제에 관하여(탄력적 검색 + 장고), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/lyamaa/elastic-search-django-g85텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)