您的位置:首页 > 科技 > IT业 > 河源网站搭建费用_邢台贴吧打黑最新消息_购物网站大全_seo搜索优化推广

河源网站搭建费用_邢台贴吧打黑最新消息_购物网站大全_seo搜索优化推广

2024/10/6 5:57:51 来源:https://blog.csdn.net/m0_66925868/article/details/142529803  浏览:    关键词:河源网站搭建费用_邢台贴吧打黑最新消息_购物网站大全_seo搜索优化推广
河源网站搭建费用_邢台贴吧打黑最新消息_购物网站大全_seo搜索优化推广

文章目录

    • 集成ES到django restful服务端项目
      • 安装haystack
      • 基本使用
        • 安装配置
        • 索引模型
          • ORM模型中新增discount_json字段方法
          • 全文索引字段模板
        • 索引序列化器
        • 全文搜索的索引视图
        • 路由
        • 手动构建es索引

集成ES到django restful服务端项目

如果直接在Django项目直接编写代码作为ElasticSearch的客户端,比较复杂,所以借助第三方包Haystack来对接ELasticSearch的客户端。而且使用了Haystack后,以后你换其他的全文搜索服务器时,也不用修改Django项目已经写好的代码。

安装haystack

Haystack ,Django ,Elasticsearch 三者之间的关系是:

  1. Haystack 作为 Django 的一个插件,提供了一个 Django 应用接口来实现搜索功能。
  2. Elasticsearch 作为 Haystack 支持的搜索引擎之一,可以被 Haystack 用来作为后端搜索引擎来存储检索数据。
  3. 当你在 Django 项目中使用 Haystack 并选择 Elasticsearch 作为搜索引擎时,Haystack 会作为中间层,让你能够通过 Django 的视图和模板来操作 Elasticsearch,实现全文搜索的功能

简单来说,Haystack 为 Django 提供了搜索功能的抽象层,而 Elasticsearch 是这个抽象层背后的具体实现之一。通过 Haystack,你可以在 Django 项目中轻松地实现强大的搜索功能。

haystack是django的开源搜索框架,能够结合目前市面上大部分的搜索引擎用于实现自定义搜索功能,特别是全文搜索。

haystack支持多种搜索引擎,不仅仅是 jieba ,whoosh,使用solr、elasticsearch等搜索,也可通过haystack,而且直接切换引擎即可,甚至无需修改搜索代码。中文分词最好的就是jieba和elasticsearch+ik。

github: https://github.com/rhblind/drf-haystack

# python操作elasticsearch的模块,注意对应版本,类似pymysql
pip install -U elasticsearch==7.13.4
# django开发的haystack的模块,务必先安装drf`-haystack,接着才安装django-haystack。因为drf-haystack不支持es7
pip install -U drf-haystack
pip install -U django-haystack

基本使用

安装配置

文档:https://drf-haystack.readthedocs.io/en/latest/01_intro.html#examples

INSTALLED_APPS = [# 必须在自己创建的子应用前面'haystack',# 自己创建的子应用
]# haystack连接elasticsearch的配置信息
HAYSTACK_CONNECTIONS = {'default': {# haystack操作es的核心模块'ENGINE': 'haystack.backends.elasticsearch7_backend.Elasticsearch7SearchEngine',# es服务端地址'URL': 'http://127.0.0.1:9200/',# es索引仓库'INDEX_NAME': 'haystack',},
}# 当mysqlORM操作数据库改变时,自动更新es的索引,否则es的索引会找不到新增的数据
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
索引模型

在courses子应用下创建search_indexes.py,用于设置es的索引模型。注意,索引模型的文件名必须是search_indexes。

  1. 类名必须为需要检索的Model_name+Index
  2. 每个索引里面必须有且只能有一个字段为 document=True,这代表haystack 和搜索引擎将使用此字段的内容作为索引进行检索(primary field)。其他的字段只是附属的属性,方便调用,并不作为检索数据。
  3. 如果使用一个字段设置了document=True,则一般约定此字段名为text,这是在SearchIndex类里面一贯的命名,以防止后台混乱,当然名字你也可以随便改,不过不建议改。
  4. haystack提供了use_template=True在text字段,这样就允许我们使用数据模板去建立搜索引擎索引的文件,说得通俗点就是索引里面需要存放一些什么东西
  5. text字段用于构造索引,只不过具体构造索引的值写在另一个文件内。
  6. id、title、digest、content、image_url等字段用于以索引查询到的返回内容。
  7. get_model方法用于指明建立索引的对应模型。
  8. index_queryset方法用于返回建立索引的数据查询集。
from haystack import indexes
from .models import Courseclass CourseIndex(indexes.SearchIndex, indexes.Indexable):# 全文索引[可以根据配置,可以包括多个字段索引]# document=True 表示当前字段为全文索引# use_template=True 表示接下来haystack需要加载一个固定路径的html模板文件,让text与其他索引字段绑定映射关系text = indexes.CharField(document=True, use_template=True)# 普通索引[单字段,只能提供单个字段值的搜索,所以此处的声明更主要是为了提供给上面的text全文索引使用的]# es索引名 = indexes.索引数据类型(model_attr="ORM中的字段名")id = indexes.IntegerField(model_attr="id")name = indexes.CharField(model_attr="name")description = indexes.CharField(model_attr="description")teacher = indexes.CharField(model_attr="teacher__name")course_cover = indexes.CharField(model_attr="course_cover")get_level_display=indexes.CharField(model_attr="get_level_display")students=indexes.IntegerField(model_attr="students")get_status_display=indexes.CharField(model_attr="get_status_display")lessons=indexes.IntegerField(model_attr="lessons")pub_lessons=indexes.IntegerField(model_attr="pub_lessons")price=indexes.DecimalField(model_attr="price")discount=indexes.CharField(model_attr="discount_json")orders=indexes.IntegerField(model_attr="orders")# 指定与当前es索引模型对接的mysql的ORM模型def get_model(self):return Course# 当用户搜索es索引时,对应的提供的mysql数据集有哪些?def index_queryset(self, using=None):return self.get_model().objects.filter(is_deleted=False,is_show=True)
ORM模型中新增discount_json字段方法

courses.models,代码:

import jsonclass Course(BaseModel):course_type = ((0, '付费购买'),(1, '会员专享'),(2, '学位课程'),)level_choices = ((0, '初级'),(1, '中级'),(2, '高级'),)status_choices = ((0, '上线'),(1, '下线'),(2, '预上线'),)# course_cover = models.ImageField(upload_to="course/cover", max_length=255, verbose_name="封面图片", blank=True, null=True)course_cover = StdImageField(variations={'thumb_1080x608': (1080, 608),   # 高清图'thumb_540x304': (540, 304),    # 中等比例,'thumb_108x61': (108, 61, True),  # 小图(第三个参数表示保持图片质量),}, max_length=255, delete_orphans=True, upload_to="course/cover", null=True, verbose_name="封面图片",blank=True)course_video = models.FileField(upload_to="course/video", max_length=255, verbose_name="封面视频", blank=True, null=True)course_type = models.SmallIntegerField(choices=course_type,default=0, verbose_name="付费类型")level = models.SmallIntegerField(choices=level_choices, default=1, verbose_name="难度等级")description = RichTextUploadingField(null=True, blank=True, verbose_name="详情介绍")pub_date = models.DateField(auto_now_add=True, verbose_name="发布日期")period = models.IntegerField(default=7, verbose_name="建议学习周期(day)")attachment_path = models.FileField(max_length=1000, blank=True, null=True, verbose_name="课件路径")attachment_link = models.CharField(max_length=1000, blank=True, null=True, verbose_name="课件链接")status = models.SmallIntegerField(choices=status_choices, default=0, verbose_name="课程状态")students = models.IntegerField(default=0, verbose_name="学习人数")lessons = models.IntegerField(default=0, verbose_name="总课时数量")pub_lessons = models.IntegerField(default=0, verbose_name="已更新课时数量")price = models.DecimalField(max_digits=10,decimal_places=2, verbose_name="课程原价",default=0)recomment_home_hot = models.BooleanField(default=False, verbose_name="是否推荐到首页新课栏目")recomment_home_top = models.BooleanField(default=False, verbose_name="是否推荐到首页必学栏目")direction = models.ForeignKey("CourseDirection", related_name="course_list", on_delete=models.DO_NOTHING, null=True, blank=True, db_constraint=False, verbose_name="学习方向")category = models.ForeignKey("CourseCategory", related_name="course_list", on_delete=models.DO_NOTHING, null=True, blank=True, db_constraint=False, verbose_name="课程分类")teacher = models.ForeignKey("Teacher", related_name="course_list", on_delete=models.DO_NOTHING, null=True, blank=True, db_constraint=False, verbose_name="授课老师")class Meta:db_table = "fg_course_info"verbose_name = "课程信息"verbose_name_plural = verbose_namedef __str__(self):return "%s" % self.namedef course_cover_small(self):if self.course_cover:return mark_safe(f'<img style="border-radius: 0%;" src="{self.course_cover.thumb_108x61.url}">')return ""course_cover_small.short_description = "封面图片(108x61)"course_cover_small.allow_tags = Truecourse_cover_small.admin_order_field = "course_cover"def course_cover_medium(self):if self.course_cover:return mark_safe(f'<img style="border-radius: 0%;" src="{self.course_cover.thumb_540x304.url}">')return ""course_cover_medium.short_description = "封面图片(540x304)"course_cover_medium.allow_tags = Truecourse_cover_medium.admin_order_field = "course_cover"def course_cover_large(self):if self.course_cover:return mark_safe(f'<img style="border-radius: 0%;" src="{self.course_cover.thumb_1080x608.url}">')return ""course_cover_large.short_description = "封面图片(1080x608)"course_cover_large.allow_tags = Truecourse_cover_large.admin_order_field = "course_cover"@propertydef discount(self):# todo 将来通过计算获取当前课程的折扣优惠相关的信息import randomreturn {"type": ["限时优惠","限时减免"].pop(random.randint(0,1)), # 优惠类型"expire": random.randint(100000, 1200000),  #  优惠倒计时"price": float(self.price - random.randint(1,10) * 10),  # 优惠价格}def discount_json(self):# 必须转成字符串才能保存到es中。所以该方法提供给es使用的。return json.dumps(self.discount)
全文索引字段模板

全文索引模板必须先配置django项目中的TEMPLATES模板引擎路径,而且全文索引模板的路径必须是模板目录下的search/indexes/子应用目录名/模型类名_text.txt。否则报错。settings.dev,代码:

TEMPLATES = [{'BACKEND': 'django.template.backends.django.DjangoTemplates','DIRS': [BASE_DIR / "templates",  # BASE_DIR 是apps的父级目录,是主应用目录,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',],},},
]

创建全文索引字段的html模板,在HTML模板中采用django的模板语法,绑定text与其他es单字段索引的映射关系。

注意:course_text.txt 中course就是ORM模型类名小写,text就是es索引模型类中的全文索引字段名。

templates/search/indexes/courses/course_text.txt。代码:

{{ object.name }}
{{ object.description }}
{{ object.teacher.name }}
{{ object.category.name }}
{{ object.diretion.name }}

object表示当前orm的模型对应。

在这里插入图片描述

在这里插入图片描述

索引序列化器

courses.serializers,代码:

from drf_haystack.serializers import HaystackSerializer
from .search_indexes import CourseIndex
from django.conf import settingsclass  CourseIndexHaystackSerializer(HaystackSerializer):"""课程搜索的序列化器"""class Meta:index_classes = [CourseIndex]fields = ["text", "id", "name", "course_cover", "get_level_display", "students", "get_status_display", "pub_lessons", "price", "discount", "orders"]def to_representation(self, instance):"""用于指定返回数据的字段的"""# 课程的图片,在这里通过elasticsearch提供的,所以不会提供图片地址左边的域名的。因此在这里手动拼接instance.course_cover = f'//{settings.OSS_BUCKET_NAME}.{settings.OSS_ENDPOINT}/uploads/{instance.course_cover}'return super().to_representation(instance)
全文搜索的索引视图
from drf_haystack.viewsets import HaystackViewSet
from drf_haystack.filters import HaystackFilter
from .serializers import CourseIndexHaystackSerializer
from .models import Courseclass CourseSearchViewSet(HaystackViewSet):"""课程信息全文搜索视图类"""# 指定本次搜索的最终真实数据的保存模型index_models = [Course]serializer_class = CourseIndexHaystackSerializerfilter_backends = [OrderingFilter, HaystackFilter]ordering_fields = ('id', 'students', 'orders')pagination_class = CourseListPageNumberPagination
路由
from django.urls import path,re_path
from . import viewsfrom rest_framework import routers
router = routers.DefaultRouter()
# 注册全文搜索到视图集中生成url路由信息
router.register("search", views.CourseSearchViewSet, basename="course-search")urlpatterns = [path("directions/", views.CourseDirectionListAPIView.as_view()),re_path("^categories/(?P<direction>\d+)/$", views.CourseCategoryListAPIView.as_view()),re_path("^(?P<direction>\d+)/(?P<category>\d+)/$", views.CourseListAPIView.as_view()),
] + router.urls
手动构建es索引

因为此前mysql中已经有了部分的数据,而这部分数据在es中是没有创建索引。所以需要先把之前的数据同步生成全文索引。在终端下执行以下命令

# 重建索引
python manage.py rebuild_index# 更新索引
# python manage.py update_index --age=<num_hours># 删除索引
# python manage.py clear_index

访问

http://api.fuguang.cn:8000/courses/search/?text=入门

http://api.fuguang.cn:8000/courses/search/?text=李老师

在这里插入图片描述

若有错误与不足请指出,关注DPT一起进步吧!!!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com