当前位置: 首页 > news >正文

【Django开发】前后端分离django美多商城项目第15篇:商品搜索,1. Haystack介绍和安装配置【附代码文档】

本教程的知识点为: 项目准备 项目准备 配置 1. 修改settings/dev.py 文件中的路径信息 2. INSTALLED_APPS 3. 数据库 用户部分 图片 1. 后端接口设计: 视图原型 2. 具体视图实现 用户部分 使用Celery完成发送 判断帐号是否存在 1. 判断用户名是否存在 后端接口设计: 用户部分 JWT 什么是JWT 起源 传统的session认证 用户部分 登录 1. 业务说明 2. 后端接口设计 3. 后端实现 登录 使用登录的流程 创建模型类 urllib使用说明 登录回调处理 登录 使用登录的流程 创建模型类 urllib使用说明 绑定用户身份接口 邮件与验证 学习目标: 业务说明: 技术说明: 保存邮箱并发送验证邮件 省市区地址查询 数据库建表 说明 页面静态化 注意 定时任务 安装 部分 详情页 异步任务的触发 。 后端接口设计 收货地址 使用缓存 安装 使用方法 为省市区视图添加缓存 数据库表设计 表结构 数据表结构 首页数据表结构 Docker使用 Docker简介 用户浏览历史记录 1. 保存 后端接口设计 后端实现 搜索 1. 需求分析 2. 搜索引擎原理 3. Elasticsearch 部分 业务需求分析 技术实现 数据存储设计 1. Redis保存已登录用户 商品部分 业务需求分析 技术实现 查询数据 1. 后端接口设计 部分 业务需求分析 技术实现 登录合并 修改登录视图 部分 保存 1. 后端接口设计 2. 后端实现 保存的思路 创建数据库模型类 接入 开发平台登录 沙箱环境 Xadmin 1. 安装 2. 使用 站点的全局配置 站点Model管理。 在Ubuntu中安装 2. 启动与停止 3. 镜像操作 端与自定义文件存储系统 1. 的Python客户端 安装 使用。

完整笔记资料代码:https://gitee.com/yinuo112/Backend/tree/master/Django/前后端分离django美多商城项目/note.md

感兴趣的小伙伴可以自取哦~


全套教程部分目录:


部分文件图片:

商品搜索

Haystack扩展建立索引

提示:

  • [Elasticsearch]( 的底层是开源库 [Lucene]( Lucene,必须自己写代码去调用它的接口。

思考:

  • 我们如何对接 Elasticsearch服务端?

解决方案:

  • Haystack

1. Haystack介绍和安装配置

1.Haystack介绍

  • Haystack 是在Django中对接搜索引擎的框架,搭建了用户和搜索引擎之间的沟通桥梁。

  • 我们在Django中可以通过使用 Haystack 来调用 Elasticsearch 搜索引擎。

  • Haystack 可以在不修改代码的情况下使用不同的搜索后端(比如 ElasticsearchWhooshSolr等等)。

    2.Haystack安装

$ pip install django-haystack
$ pip install elasticsearch==2.4.1

3.Haystack注册应用和路由

INSTALLED_APPS = [
    'haystack', # 全文检索
]
url(r'^search/', include('haystack.urls')),

4.Haystack配置

  • 在配置文件中配置Haystack为搜索引擎后端
# Haystack


HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'haystack.backends.elasticsearch_backend.ElasticsearchSearchEngine',
        'URL': ' # Elasticsearch服务器ip地址,端口号固定为9200
        'INDEX_NAME': 'meiduo_mall', # Elasticsearch建立的索引库的名称
    },
}



# 当添加、修改、删除数据时,自动生成索引


HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

重要提示:

  • HAYSTACK_SIGNAL_PROCESSOR 配置项保证了在Django运行起来后,有新的数据产生时,Haystack仍然可以让Elasticsearch实时生成新数据的索引

2. Haystack建立数据索引

1.创建索引类

  • 通过创建索引类,来指明让搜索引擎对哪些字段建立索引,也就是可以通过哪些字段的关键字来检索数据。
  • 本项目中对SKU信息进行全文检索,所以在goods应用中新建search_indexes.py文件,用于存放索引类。
from haystack import indexes

from .models import SKU


class SKUIndex(indexes.SearchIndex, indexes.Indexable):
    """SKU索引数据模型类"""
    text = indexes.CharField(document=True, use_template=True)

    def get_model(self):
        """返回建立索引的模型类"""
        return SKU

    def index_queryset(self, using=None):
        """返回要建立索引的数据查询集"""
        return self.get_model().objects.filter(is_launched=True)
  • 索引类SKUIndex说明:

  • SKUIndex建立的字段,都可以借助HaystackElasticsearch搜索引擎查询。

  • 其中text字段我们声明为document=True,表名该字段是主要进行关键字查询的字段。
  • text字段的索引值可以由多个数据库模型类字段组成,具体由哪些模型类字段组成,我们用use_template=True表示后续通过模板来指明。

2.创建text字段索引值模板文件

  • templates目录中创建text字段使用的模板文件
  • 具体在templates/search/indexes/goods/sku_text.txt文件中定义
{{ object.id }}
{{ object.name }}
{{ object.caption }}
  • 模板文件说明:当将关键词通过text参数名传递时

  • 此模板指明SKU的idnamecaption作为text字段的索引值来进行关键字索引查询。

3.手动生成初始索引

$ python manage.py rebuild_index

3. 全文检索测试

1.准备测试表单

  • 请求方法:GET
  • 请求地址:/search/
  • 请求参数:q

<div class="search_wrap fl">
    <form method="get" action="/search/" class="search_con">
        <input type="text" class="input_text fl" name="q" placeholder="搜索商品">
        <input type="submit" class="input_btn fr" name="" value="搜索">
    </form>
    <ul class="search_suggest fl">
        <li><a href="#">索尼微单</a></li>
        <li><a href="#">优惠15元</a></li>
        <li><a href="#">美妆个护</a></li>
        <li><a href="#">买2免1</a></li>
    </ul>
</div>

2.全文检索测试结果

结论:

  • 错误提示告诉我们在templates/search/目录中缺少一个search.html文件
  • search.html文件作用就是接收和渲染全文检索的结果

渲染商品搜索结果

1. 准备商品搜索结果页面

2. 渲染商品搜索结果

Haystack返回的数据包括:

  • query:搜索关键字
  • paginator:分页paginator对象
  • page:当前页的page对象(遍历page中的对象,可以得到result对象)
  • result.objects: 当前遍历出来的SKU对象。
<div class="main_wrap clearfix">
    <div class=" clearfix">
        <ul class="goods_type_list clearfix">
            {% for result in page %}
            <li>
                {# object取得才是sku对象 #}
                <a href="/detail/{{ result.object.id }}/"><img src="{{ result.object.default_image.url }}"></a>
                <h4><a href="/detail/{{ result.object.id }}/">{{ result.object.name }}</a></h4>
                <div class="operate">
                    <span class="price">¥{{ result.object.price }}</span>
                    <span>{{ result.object.comments }}评价</span>
                </div>
            </li>
            {% else %}
                <p>没有找到您要查询的商品。</p>
            {% endfor %}
        </ul>
        <div class="pagenation">
            <div id="pagination" class="page"></div>
        </div>
    </div>
</div>

3. Haystack搜索结果分页

1.设置每页返回数据条数

  • 通过HAYSTACK_SEARCH_RESULTS_PER_PAGE可以控制每页显示数量
  • 每页显示五条数据:HAYSTACK_SEARCH_RESULTS_PER_PAGE = 5

    2.准备搜索页分页器

<div class="main_wrap clearfix">
    <div class=" clearfix">
        ......
        <div class="pagenation">
            <div id="pagination" class="page"></div>
        </div>
    </div>
</div>
<script type="text/javascript">
    $(function () {
        $('#pagination').pagination({
            currentPage: {{ page.number }},
            totalPage: {{ paginator.num_pages }},
            callback:function (current) {
                {#window.location.href = '/search/?q=iphone&amp;page=1';#}
                window.location.href = '/search/?q={{ query }}&page=' + current;
            }
        })
    });
</script>

商品详情页

商品详情页分析和准备

1. 商品详情页组成结构分析

1.商品频道分类

  • 已经提前封装在contents.utils.py文件中,直接调用方法即可。

    2.面包屑导航

  • 已经提前封装在goods.utils.py文件中,直接调用方法即可。

    3.热销排行

  • 该接口已经在商品列表页中实现完毕,前端直接调用接口即可。

    4.商品SKU信息(详情信息)

  • 通过sku_id可以找到SKU信息,然后渲染模板即可。

  • 使用Ajax实现局部刷新效果。

    5.SKU规格信息

  • 通过SKU可以找到SPU规格和SKU规格信息。

    6.商品详情介绍、规格与包装、售后服务

  • 通过SKU可以找到SPU信息,SPU中可以查询出商品详情介绍、规格与包装、售后服务。

    7.商品评价

  • 商品评价需要在生成了订单,对订单商品进行评价后再实现,商品评价信息是动态数据。

  • 使用Ajax实现局部刷新效果。

2. 商品详情页接口设计和定义

1.请求方式

选项方案
请求方法GET
请求地址/detail/(?P\d+)/
>
2.请求参数:路径参数
参数名类型是否必传说明
sku_idstring商品SKU编号
>
3.响应结果:HTML
detail.html

4.接口定义

class DetailView(View):
    """商品详情页"""

    def get(self, request, sku_id):
        """提供商品详情页"""
        return render(request, 'detail.html')

3. 商品详情页初步渲染

渲染商品频道分类、面包屑导航、商品热销排行

  • 将原先在商品列表页实现的代码拷贝到商品详情页即可。
  • 添加detail.js
class DetailView(View):
    """商品详情页"""

    def get(self, request, sku_id):
        """提供商品详情页"""
        # 获取当前sku的信息
        try:
            sku = models.SKU.objects.get(id=sku_id)
        except models.SKU.DoesNotExist:
            return render(request, '404.html')

        # 查询商品频道分类
        categories = get_categories()
        # 查询面包屑导航
        breadcrumb = get_breadcrumb(sku.category)

        # 渲染页面
        context = {
            'categories':categories,
            'breadcrumb':breadcrumb,
            'sku':sku,
        }
        return render(request, 'detail.html', context)

提示:为了让前端在获取商品热销排行数据时,能够拿到商品分类ID,我们将商品分类ID从模板传入到Vue.js

<script type="text/javascript">
    let category_id = "{{ sku.category.id }}";
</script>
data: {
    category_id: category_id,
},

展示详情页数据

1. 查询和渲染SKU详情信息

# 渲染页面


context = {
    'categories':categories,
    'breadcrumb':breadcrumb,
    'sku':sku,
}
return render(request, 'detail.html', context)
<div class="goods_detail_con clearfix">
    <div class="goods_detail_pic fl"><img src="{{ sku.default_image.url }}"></div>
    <div class="goods_detail_list fr">
        <h3>{{ sku.name }}</h3>
        <p>{{ sku.caption }}</p>
        <div class="price_bar">
            <span class="show_pirce">¥<em>{{ sku.price }}</em></span>
            <a href="javascript:;" class="goods_judge">18人评价</a>
        </div>
        <div class="goods_num clearfix">
            <div class="num_name fl">数 量:</div>
            <div class="num_add fl">
                <input v-model="sku_count" @blur="check_sku_count" type="text" class="num_show fl">
                <a @click="on_addition" class="add fr">+</a>
                <a @click="on_minus" class="minus fr">-</a>
            </div> 
        </div>
        {#...商品规格...#}
        <div class="total" v-cloak>总价:<em>[[ sku_amount ]]元</em></div>
        <div class="operate_btn">
            <a href="javascript:;" class="add_cart" id="add_cart">加入购物车</a>                
        </div>
    </div>
</div>

提示:为了实现用户选择商品数量的局部刷新效果,我们将商品单价从模板传入到Vue.js

<script type="text/javascript">
    let sku_price = "{{ sku.price }}";
</script>
data: {
    sku_price: sku_price,
},

2. 查询和渲染SKU规格信息

1.查询SKU规格信息

class DetailView(View):
    """商品详情页"""

    def get(self, request, sku_id):
        """提供商品详情页"""
        # 获取当前sku的信息
        try:
            sku = models.SKU.objects.get(id=sku_id)
        except models.SKU.DoesNotExist:
            return render(request, '404.html')

        # 查询商品频道分类
        categories = get_categories()
        # 查询面包屑导航
        breadcrumb = get_breadcrumb(sku.category)

        # 构建当前商品的规格键
        sku_specs = sku.specs.order_by('spec_id')
        sku_key = []
        for spec in sku_specs:
            sku_key.append(spec.option.id)
        # 获取当前商品的所有SKU
        skus = sku.spu.sku_set.all()
        # 构建不同规格参数(选项)的sku字典
        spec_sku_map = {}
        for s in skus:
            # 获取sku的规格参数
            s_specs = s.specs.order_by('spec_id')
            # 用于形成规格参数-sku字典的键
            key = []
            for spec in s_specs:
                key.append(spec.option.id)
            # 向规格参数-sku字典添加记录
            spec_sku_map[tuple(key)] = s.id
        # 获取当前商品的规格信息
        goods_specs = sku.spu.specs.order_by('id')
        # 若当前sku的规格信息不完整,则不再继续
        if len(sku_key) < len(goods_specs):
            return
        for index, spec in enumerate(goods_specs):
            # 复制当前sku的规格键
            key = sku_key[:]
            # 该规格的选项
            spec_options = spec.options.all()
            for option in spec_options:
                # 在规格参数sku字典中查找符合当前规格的sku
                key[index] = option.id
                option.sku_id = spec_sku_map.get(tuple(key))
            spec.spec_options = spec_options

        # 渲染页面
        context = {
            'categories':categories,
            'breadcrumb':breadcrumb,
            'sku':sku,
            'specs': goods_specs,
        }
        return render(request, 'detail.html', context)

2.渲染SKU规格信息

{% for spec in specs %}
<div class="type_select">
    <label>{{ spec.name }}:</label>
    {% for option in spec.spec_options %}
        {% if option.sku_id == sku.id %}
        <a href="javascript:;" class="select">{{ option.value }}</a>
        {% elif option.sku_id %}
        <a href="{{ url('goods:detail', args=(option.sku_id, )) }}">{{ option.value }}</a>
        {% else %}
        <a href="javascript:;">{{ option.value }}</a>
        {% endif %}
    {% endfor %}
</div>
{% endfor %}

3. 查询和渲染详情、包装和售后信息

商品详情、包装和售后信息被归类到商品SPU中,sku.spu关联查询就可以找到该SKUSPU信息。

<div class="r_wrap fr clearfix">
    <ul class="detail_tab clearfix">
        <li @click="on_tab_content('detail')" :class="tab_content.detail?'active':''">商品详情</li>
        <li @click="on_tab_content('pack')" :class="tab_content.pack?'active':''">规格与包装</li>
        <li @click="on_tab_content('service')" :class="tab_content.service?'active':''">售后服务</li>
        <li @click="on_tab_content('comment')" :class="tab_content.comment?'active':''">商品评价(18)</li>
    </ul>
    <div @click="on_tab_content('detail')" class="tab_content" :class="tab_content.detail?'current':''">
        <dl>
            <dt>商品详情:</dt>
            <dd>{{ sku.spu.desc_detail|safe }}</dd>
        </dl>
    </div>
    <div @click="on_tab_content('pack')" class="tab_content" :class="tab_content.pack?'current':''">
        <dl>
            <dt>规格与包装:</dt>
            <dd>{{ sku.spu.desc_pack|safe }}</dd>
        </dl>
    </div>
    <div @click="on_tab_content('service')" class="tab_content" :class="tab_content.service?'current':''">
        <dl>
            <dt>售后服务:</dt>
            <dd>{{ sku.spu.desc_service|safe }}</dd>
        </dl>
    </div>
    <div @click="on_tab_content('comment')" class="tab_content" :class="tab_content.comment?'current':''">
        <ul class="judge_list_con">
            {#...商品评价...#}
        </ul>
    </div>
</div>
http://www.dtcms.com/a/106631.html

相关文章:

  • 从 ZStack 获取物理机与云主机信息并导出 Excel 文件
  • visual studio 2022的windows驱动开发
  • C# System.Text.Json 中 JsonIgnoreCondition 使用详解
  • Linux2 CD LL hostnamectl type mkdir dudo
  • 跨系统平台实践:在内网自建kylin服务版系统yum源
  • 面基JavaEE银行金融业务逻辑层处理金融数据类型BigDecimal
  • AI提示词:好评生成器
  • 鸿蒙NEXT小游戏开发:数字华容道
  • 详解相机的内参和外参,以及内外参的标定方法
  • 背包DP总结
  • GO语言 使用protobuf
  • 【第十三届“泰迪杯”数据挖掘挑战赛】【2025泰迪杯】【代码篇】A题解题全流程(持续更新)
  • 全国产ADC 16bit 2通道1G采样 双FMC子板
  • C++多继承
  • 【抓包工具】win 10 / win 11:Charles 下载、安装、配置(快捷方式、默认端口、登录、https 证书)
  • 【git】VScode修改撤回文件总是出现.lh文件,在 ​所有 Git 项目 中全局忽略特定文件
  • MacOS 的 AI Agent 新星,本地沙盒驱动,解锁 macOS 操作新体验!
  • 地表-地下水系统交互模拟关键技术突破:SWAT-MODFLOW耦合模型构建、验证及多情景预测研究
  • 离线语音识别 ( 小语种国家都支持)可定制词组
  • 项目管理管什么?理什么?
  • 《云端都市:云计算如何重塑未来城市形态》
  • spikingjelly:使用单层全连接 SNN 识别 MNIST
  • Java UnsupportedOperationException 深度解析及解决方案
  • 在HarmonyOS NEXT 开发中,如何指定一个号码,拉起系统拨号页面
  • Python从入门到精通4:计算机网络及TCP网络应用程序开发入门指南
  • JuiceFS vs HDFS,最简单的 JuiceFS 入门
  • Muduo网络库实现 [八] - Acceptor模块
  • 【Harmony OS】TypeScrip基础
  • 小米汽车就 SU7 事故回应六点问题,称「事故车起火并非自燃」、「无法分析车门能否打开」,如何看待?
  • 从头开发一个Flutter插件(二)高德地图定位插件