Django电商项目(六)商品详情页、列表页分页、商品搜索

商品详情页

新建detail.html

{% extends 'base_detail_list.html' %}
{% block title %}天天生鲜-商品详情{% endblock title %}

{% block main_content %}
	<div class="breadcrumb">
		<a href="#">全部分类</a>
		<span>></span>
		<a href="#">{
   
   { sku.type.name }}</a>
		<span>></span>
		<a href="#">商品详情</a>
	</div>

	<div class="goods_detail_con clearfix">
		<div class="goods_detail_pic fl"><img src="{
     
     { sku.image.url }}"></div>

		<div class="goods_detail_list fr">
			<h3>{
   
   { sku.name }}</h3>
			<p>{
   
   { sku.desc }}</p>
			<div class="prize_bar">
				<span class="show_pirze">¥<em>{
   
   { sku.price }}</em></span>
				<span class="show_unit">单  位:{
   
   { sku.unite }}</span>
			</div>
			<div class="goods_num clearfix">
				<div class="num_name fl">数 量:</div>
				<div class="num_add fl">
					<input type="text" class="num_show fl" value="1">
					<a href="javascript:;" class="add fr">+</a>
					<a href="javascript:;" class="minus fr">-</a>	
				</div> 
			</div>
            <div>
                <p>其他规格:</p>
                <ul>
                    {% for sku in same_spu_skus %}
                        <li><a href="{% url 'goods:detail' sku.id %}">{
   
   { sku.name }}</a></li>
                    {% endfor %}
                </ul>
            </div>
			<div class="total">总价:<em>16.80元</em></div>
			<div class="operate_btn">
				<a href="javascript:;" class="buy_btn">立即购买</a>
				<a href="javascript:;" class="add_cart" id="add_cart">加入购物车</a>				
			</div>
		</div>
	</div>

	<div class="main_wrap clearfix">
		<div class="l_wrap fl clearfix">
			<div class="new_goods">
				<h3>新品推荐</h3>
				<ul>
                    {% for sku in new_skus %}
					<li>
						<a href="{% url 'goods:detail' sku.id %}"><img src="{
     
     { sku.image.url }}"></a>
						<h4><a href="{% url 'goods:detail' sku.id %}">{
   
   { sku.name }}</a></h4>
						<div class="prize">¥{
   
   { sku.price }}</div>
					</li>
					{% endfor %}
				</ul>
			</div>
		</div>

		<div class="r_wrap fr clearfix">
			<ul class="detail_tab clearfix">
				<li class="active">商品介绍</li>
				<li>评论</li>
			</ul>

			<div class="tab_content">
				<dl>
					<dt>商品详情:</dt>
                    <dd>{
   
   { sku.goods.detail|safe }}</dd>
				</dl>
			</div>

            <div class="tab_content">
				<dl>
                    {% for order in sku_orders %}
					<dt>评论时间:{
   
   { order.update_time }}&nbsp;&nbsp;用户名:{
   
   { order.order.user.username }}</dt>
                    <dd>评论内容:{
   
   { order.comment }}</dd>
                    {% endfor %}
				</dl>
			</div>
		</div>
	</div>
{% endblock main_content %}
{% block bottom %}
	<div class="add_jump"></div>
{% endblock bottom %}
{% block bottomfiles %}
	<script type="text/javascript" src="js/jquery-1.12.2.js"></script>
	<script type="text/javascript">
		var $add_x = $('#add_cart').offset().top;
		var $add_y = $('#add_cart').offset().left;

		var $to_x = $('#show_count').offset().top;
		var $to_y = $('#show_count').offset().left;

		$(".add_jump").css({
      
      'left':$add_y+80,'top':$add_x+10,'display':'block'})
		$('#add_cart').click(function(){
      
      
			$(".add_jump").stop().animate({
      
      
				'left': $to_y+7,
				'top': $to_x+7},
				"fast", function() {
      
      
					$(".add_jump").fadeOut('fast',function(){
      
      
						$('#show_count').html(2);
					});

			});
		})
	</script>
{% endblock bottomfiles %}

view.py

# /goods/商品id
class DetailView(View):
    '''详情页'''
    def get(self, request, goods_id):
        '''显示详情页'''
        try:
            sku = GoodsSKU.objects.get(id=goods_id)
        except GoodsSKU.DoesNotExist:
            # 商品不存在
            return redirect(reverse('goods:index'))

        # 获取商品的分类信息
        types = GoodsType.objects.all()

        # 获取商品的评论信息
        sku_orders = OrderGoods.objects.filter(sku=sku).exclude(comment='')

        # 获取新品信息
        new_skus = GoodsSKU.objects.filter(type=sku.type).order_by('-create_time')[:2]

        # 获取同一个SPU的其他规格商品
        same_spu_skus = GoodsSKU.objects.filter(goods=sku.goods).exclude(id=goods_id)

        # 获取用户购物车中商品的数目
        user = request.user
        cart_count = 0
        if user.is_authenticated():
            # 用户已登录
            conn = get_redis_connection('default')
            cart_key = 'cart_%d' % user.id
            cart_count = conn.hlen(cart_key)

            # 添加用户的历史记录
            conn = get_redis_connection('default')
            history_key = 'history_%d'%user.id
            # 移除列表中的goods_id
            conn.lrem(history_key, 0, goods_id)
            # 把goods_id插入到列表的左侧
            conn.lpush(history_key, goods_id)
            # 只保存用户最新浏览的5条信息
            conn.ltrim(history_key, 0, 4)

        # 组织模板上下文
        context = {
    
    'sku':sku, 'types':types,
                   'sku_orders':sku_orders,
                   'new_skus':new_skus,
                   'same_spu_skus':same_spu_skus,
                   'cart_count':cart_count}

        # 使用模板
        return render(request, 'detail.html', context)

商品列表页

修改list.html文件

{% extends 'base_detail_list.html' %}
{% block title %}天天生鲜-商品列表{% endblock title %}
{% block main_content %}
	<div class="breadcrumb">
		<a href="#">全部分类</a>
		<span>></span>
		<a href="#">{
   
   { type.name }}</a>
	</div>

	<div class="main_wrap clearfix">
		<div class="l_wrap fl clearfix">
			<div class="new_goods">
				<h3>新品推荐</h3>
				<ul>
                    {% for sku in new_skus %}
					<li>
						<a href="{% url 'goods:detail' sku.id %}"><img src="{
     
     { sku.image.url }}"></a>
						<h4><a href="{% url 'goods:detail' sku.id %}">{
   
   { sku.name }}</a></h4>
						<div class="prize">¥{
   
   { sku.price }}</div>
					</li>
                    {% endfor %}
				</ul>
			</div>
		</div>

		<div class="r_wrap fr clearfix">
			<div class="sort_bar">
				<a href="{% url 'goods:list' type.id 1 %}" {% if sort == 'default' %}class="active"{% endif %}>默认</a>
				<a href="{% url 'goods:list' type.id 1 %}?sort=price" {% if sort == 'price' %}class="active"{% endif %}>价格</a>
				<a href="{% url 'goods:list' type.id 1 %}?sort=hot" {% if sort == 'hot' %}class="active"{% endif %}>人气</a>
			</div>

			<ul class="goods_type_list clearfix">
                {% for sku in skus_page %}
				<li>
					<a href="{% url 'goods:detail' sku.id %}"><img src="{
     
     { sku.image.url }}"></a>
					<h4><a href="{% url 'goods:detail' sku.id %}">{
   
   { sku.name }}</a></h4>
					<div class="operate">
						<span class="prize">¥{
   
   { sku.price }}</span>
						<span class="unit">{
   
   { sku.price}}/{
   
   { sku.unite }}</span>
						<a href="#" class="add_goods" title="加入购物车"></a>
					</div>
				</li>
                {% endfor %}
			</ul>

			<div class="pagenation">
                {% if skus_page.has_previous %}
				<a href="{% url 'goods:list' type.id skus_page.previous_page_number %}?sort={
     
     { sort }}"><上一页</a>
                {% endif %}
                {% for pindex in skus_page.paginator.page_range %}
                    {% if pindex == skus_page.number %}
				        <a href="{% url 'goods:list' type.id pindex %}?sort={
     
     { sort }}" class="active">{
   
   { pindex }}</a>
                    {% else %}
				        <a href="{% url 'goods:list' type.id pindex %}?sort={
     
     { sort }}">{
   
   { pindex }}</a>
                    {% endif %}
				{% endfor %}
                {% if skus_page.has_next %}
				<a href="{% url 'goods:list' type.id skus_page.next_page_number %}?sort={
     
     { sort }}">下一页></a>
                {% endif %}
			</div>
		</div>
	</div>
{% endblock main_content %}

定义view.py
分页导入
from django.core.paginator import Paginator
分页参考文档
https://doc.codingdict.com/django/topics/pagination.html


# 种类id 页码 排序方式
# restful api -> 请求一种资源
# /list?type_id=种类id&page=页码&sort=排序方式
# /list/种类id/页码/排序方式
# /list/种类id/页码?sort=排序方式
class ListView(View):
    '''列表页'''
    def get(self, request, type_id, page):
        '''显示列表页'''
        # 获取种类信息
        try:
            type = GoodsType.objects.get(id=type_id)
        except GoodsType.DoesNotExist:
            # 种类不存在
            return redirect(reverse('goods:index'))

        # 获取商品的分类信息
        types = GoodsType.objects.all()

        # 获取排序的方式 # 获取分类商品的信息
        # sort=default 按照默认id排序
        # sort=price 按照商品价格排序
        # sort=hot 按照商品销量排序
        sort = request.GET.get('sort')

        if sort == 'price':
            skus = GoodsSKU.objects.filter(type=type).order_by('price')
        elif sort == 'hot':
            skus = GoodsSKU.objects.filter(type=type).order_by('-sales')
        else:
            sort = 'default'
            skus = GoodsSKU.objects.filter(type=type).order_by('-id')

        # 对数据进行分页
        paginator = Paginator(skus, 1)

        # 获取第page页的内容
        try:
            page = int(page)
        except Exception as e:
            page = 1

        if page > paginator.num_pages:
            page = 1

        # 获取第page页的Page实例对象
        skus_page = paginator.page(page)

        # todo: 进行页码的控制,页面上最多显示5个页码

        # 获取新品信息
        new_skus = GoodsSKU.objects.filter(type=type).order_by('-create_time')[:2]

        # 获取用户购物车中商品的数目
        user = request.user
        cart_count = 0
        if user.is_authenticated():
            # 用户已登录
            conn = get_redis_connection('default')
            cart_key = 'cart_%d' % user.id
            cart_count = conn.hlen(cart_key)

        # 组织模板上下文
        context = {
    
    'type':type, 'types':types,
                   'skus_page':skus_page,
                   'new_skus':new_skus,
                   'cart_count':cart_count,
                   'sort':sort}

        # 使用模板
        return render(request, 'list.html', context)

配置url

url(r'^list/(?P<type_id>\d+)/(?P<page>\d+)$', ListView.as_view(), name='list'), # 列表页

商品搜索

在这里插入图片描述

全文检索

全文检索不同于特定字段的模糊查询,使用全文检索的效率更高,并且能够对于中文进行分词处理。

haystack:全文检索的框架,支持whoosh、solr、Xapian、Elasticsearc四种全文检索引擎,点击查看官方网站。
whoosh:纯Python编写的全文搜索引擎,虽然性能比不上sphinx、xapian、Elasticsearc等,但是无二进制包,程序不会莫名其妙的崩溃,对于小型的站点,whoosh已经足够使用,点击查看whoosh文档。
jieba:一款免费的中文分词包,如果觉得不好用可以使用一些收费产品。

安装和配置

  1. 安装python包。
    pip install django-haystack
    pip install whoosh
  2. 在settings.py文件中注册应用haystack并做如下配置。
    在这里插入图片描述

# 全文检索框架的配置
HAYSTACK_CONNECTIONS = {
    
    
    'default': {
    
    
        # 使用whoosh引擎
        # 'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
        'ENGINE': 'haystack.backends.whoosh_cn_backend.WhooshEngine',
        # 索引文件路径
        'PATH': os.path.join(BASE_DIR, 'whoosh_index'),
    }
}

# 当添加、修改、删除数据时,自动生成索引
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'

# 指定搜索结果每页显示的条数
HAYSTACK_SEARCH_RESULTS_PER_PAGE=1

索引文件生成

  1. 在goods应用目录下新建一个search_indexes.py文件,在其中定义一个商品索引类。
# 定义索引类
from haystack import indexes
# 导入你的模型类
from goods.models import GoodsSKU


# 指定对于某个类的某些数据建立索引
# 索引类名格式:模型类名+Index
class GoodsSKUIndex(indexes.SearchIndex, indexes.Indexable):
    # 索引字段 use_template=True指定根据表中的哪些字段建立索引文件的说明放在一个文件中
    text = indexes.CharField(document=True, use_template=True)

    def get_model(self):
        # 返回你的模型类
        return GoodsSKU

    # 建立索引的数据
    def index_queryset(self, using=None):
        return self.get_model().objects.all()

  1. 在templates下面新建目录search/indexes/goods
    goods文件名为索引的类在的应用的名字
    在这里插入图片描述

  2. 在此目录下面新建一个文件goodssku_text.txt并编辑内容如下。
    命名规则:模型类名小写_text.txt

# 指定根据表中的哪些字段建立索引数据
{
   
   { object.name }} # 根据商品的名称建立索引
{
   
   { object.desc }} # 根据商品的简介建立索引
{
   
   { object.goods.detail }} # 根据商品的详情建立索引
  1. 使用命令生成索引文件。
    python manage.py rebuild_index

全文检索的使用

  1. 配置url
    项目的url.py在这里插入图片描述

2)表单搜索时设置表单内容如下。 在这里插入图片描述

点击标题进行提交时,会通过haystack搜索数据。

  1. 全文检索结果。
    搜索出结果后,haystack会把搜索出的结果传递给templates/search目录下的search.html,传递的上下文包括:
    query:搜索关键字
    page:当前页的page对象 –>遍历page对象,获取到的是SearchResult类的实例对象,对象的属性object才是模型类的对象。
    paginator:分页paginator对象

    通过HAYSTACK_SEARCH_RESULTS_PER_PAGE 可以控制每页显示数量。
    默认20条
    在这里插入图片描述

创建search.html

{% extends 'base_detail_list.html' %}
{% block title %}天天生鲜-商品搜索结果列表{% endblock title %}
{% block main_content %}
	<div class="breadcrumb">
		<a href="#">{
   
   { query }}</a>
		<span>></span>
		<a href="#">搜索结果如下:</a>
	</div>

	<div class="main_wrap clearfix">
        <ul class="goods_type_list clearfix">
            {% for item in page %}
            <li>
                <a href="{% url 'goods:detail' item.object.id %}"><img src="{
     
     { item.object.image.url }}"></a>
                <h4><a href="{% url 'goods:detail' item.object.id %}">{
   
   { item.object.name }}</a></h4>
                <div class="operate">
                    <span class="prize">¥{
   
   { item.object.price }}</span>
                    <span class="unit">{
   
   { item.object.price}}/{
   
   { item.object.unite }}</span>
                    <a href="#" class="add_goods" title="加入购物车"></a>
                </div>
            </li>
            {% endfor %}
        </ul>
        <div class="pagenation">
                {% if page.has_previous %}
				<a href="/search?q={
     
     { query }}&page={
     
     { page.previous_page_number }}"><上一页</a>
                {% endif %}
                {% for pindex in paginator.page_range %}
                    {% if pindex == page.number %}
				        <a href="/search?q={
     
     { query }}&page={
     
     { pindex }}" class="active">{
   
   { pindex }}</a>
                    {% else %}
				        <a href="/search?q={
     
     { query }}&page={
     
     { pindex }}">{
   
   { pindex }}</a>
                    {% endif %}
				{% endfor %}
                {% if spage.has_next %}
				<a href="/search?q={
     
     { query }}&page={
     
     { page.next_page_number }}">下一页></a>
                {% endif %}
			</div>
	</div>
{% endblock main_content %}

改变分词方式

在这里插入图片描述

  1. 安装jieba分词模块。
    pip install jieba
  2. 找到虚拟环境py_django下的haystack目录。
    /home/python/.virtualenvs/bj17_py3/lib/python3.5/site-packages/haystack/backends/
  3. 在上面的目录中创建ChineseAnalyzer.py文件。
import jieba
from whoosh.analysis import Tokenizer, Token

class ChineseTokenizer(Tokenizer):
    def __call__(self, value, positions=False, chars=False,
                 keeporiginal=False, removestops=True,
                 start_pos=0, start_char=0, mode='', **kwargs):
        t = Token(positions, chars, removestops=removestops, mode=mode, **kwargs)
        seglist = jieba.cut(value, cut_all=True)
        for w in seglist:
            t.original = t.text = w
            t.boost = 1.0
            if positions:
                t.pos = start_pos + value.find(w)
            if chars:
                t.startchar = start_char + value.find(w)
                t.endchar = start_char + value.find(w) + len(w)
            yield t

def ChineseAnalyzer():
    return ChineseTokenizer()
  1. 复制whoosh_backend.py文件,改为如下名称。
    whoosh_cn_backend.py

  2. 打开复制出来的新文件,引入中文分析类,内部采用jieba分词。
    from .ChineseAnalyzer import ChineseAnalyzer

  3. 更改词语分析类。
    查找
    analyzer=StemmingAnalyzer()
    改为
    analyzer=ChineseAnalyzer()

  4. 修改settings.py文件中的配置项。
    在这里插入图片描述

  5. 重新创建索引数据
    python manage.py rebuild_index

猜你喜欢

转载自blog.csdn.net/qq_27251475/article/details/120689827