商品详情页
新建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 }} 用户名:{{ 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
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]
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
conn.lrem(history_key, 0, goods_id)
conn.lpush(history_key, goods_id)
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
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 = 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)
try:
page = int(page)
except Exception as e:
page = 1
if page > paginator.num_pages:
page = 1
skus_page = paginator.page(page)
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:一款免费的中文分词包,如果觉得不好用可以使用一些收费产品。
安装和配置
- 安装python包。
pip install django-haystack pip install whoosh - 在settings.py文件中注册应用haystack并做如下配置。
HAYSTACK_CONNECTIONS = {
'default': {
'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
索引文件生成
- 在goods应用目录下新建一个search_indexes.py文件,在其中定义一个商品索引类。
from haystack import indexes
from goods.models import GoodsSKU
class GoodsSKUIndex(indexes.SearchIndex, indexes.Indexable):
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()
-
在templates下面新建目录search/indexes/goods。 goods文件名为索引的类在的应用的名字 -
在此目录下面新建一个文件goodssku_text.txt并编辑内容如下。 命名规则:模型类名小写_text.txt
# 指定根据表中的哪些字段建立索引数据
{{ object.name }} # 根据商品的名称建立索引
{{ object.desc }} # 根据商品的简介建立索引
{{ object.goods.detail }} # 根据商品的详情建立索引
- 使用命令生成索引文件。
python manage.py rebuild_index
全文检索的使用
- 配置url
项目的url.py
2)表单搜索时设置表单内容如下。
点击标题进行提交时,会通过haystack搜索数据。
- 全文检索结果。
搜索出结果后,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 %}
改变分词方式
- 安装jieba分词模块。
pip install jieba - 找到虚拟环境py_django下的haystack目录。
/home/python/.virtualenvs/bj17_py3/lib/python3.5/site-packages/haystack/backends/ - 在上面的目录中创建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()
-
复制whoosh_backend.py文件,改为如下名称。 whoosh_cn_backend.py -
打开复制出来的新文件,引入中文分析类,内部采用jieba分词。 from .ChineseAnalyzer import ChineseAnalyzer -
更改词语分析类。 查找 analyzer=StemmingAnalyzer() 改为 analyzer=ChineseAnalyzer() -
修改settings.py文件中的配置项。 -
重新创建索引数据 python manage.py rebuild_index
|