【DailyFresh】课程记录2

商品模块的其他页面

商品模块的详情页的功能:
页面信息的显示;购物车记录的添加;商品的其他规格展示


P62 商品详情信息的获取和显示


detail.html---其父模板为base_detail_list.html
定义对应的视图

class DetailView(View):
    '''详情页'''
    def get(self, request, goods_id):
        '''显示详情页'''
    return render(request, 'df_goods/detail.html')

当用户访问页面,点击之后会跳转到对应的详情页面,需要给详情页面传递参数sku_id标识点击的是哪一个商品,因此该页面的访问地址可以设计为/goods/商品id。此时路由可以设计为
re_path(r'^goods/(?P<goods_id>\d+)$', DetailView.as_view(), name='detail')
此时详情页应该进行接收goods_id,如上get方法所示。

详情页整体来说和首页一样主要是进行信息展示。此时分析该页面需要展示的信息即为视图函数中需要查询的信息。

获取商品信息的时候进行尝试查询try...except...
查询的时候有可能查询不到,进行except抛出异常
try:
    sku = GoodsSKU.objects.get(id=goods_id)
except GoodsSKU.DoesNotExist:
    # 商品不存在,直接跳转到首页。。。为了拉客户
    return redirect(reverse("goods:index"))
    
# 获取商品的分类信息
types = GoodsType.objects.all()

# 获取商品的评论信息
# 根据表结构设计,评论信息在订单商品表中
# 根据skuid筛选订单商品信息,同时过滤掉其中为空的评论
sku_orders = OrderGoods.objects.filter(sku=sku).exclude(comment=" ")

# 获取新品推荐信息,按照创建时间进行降序排序,新品只取前两个
new_skus = GoodsSKU.objects.filter(type=sku.type).order_by('-create_time')[:2]

# 获取用户购物车中商品的数目

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

根据传过来的值修改相应的模板

捕获id,查询相应的数据,在页面上进行遍历显示

P61 用户历史浏览记录的添加

此时详情页面已经开发完毕,接下来访问首页中的链接应该跳转到详情页。故将首页中的链接进行修改【使用反向解析】
{% for banner in type.title_banners %}
{% url 'goods:detail' banner.sku.id %}
{% endfor %}

关于用户中心的历史浏览记录:
什么时候需要添加历史浏览记录?
访问商品的详情页面的时候(在商品详情对应的视图中),需要添加历史浏览记录

用户登录之后:1.获取用户购物车中商品的数目;2.添加用户的历史记录

添加历史浏览记录时,用户最新浏览的商品id从列表左侧插入 
考虑如下情况:
用户浏览[3,2,1],之后用户又重新浏览2。此时的处理方案,先将2删除,随后又将2放到最左边。因此,访问时需要先看下列表中是否包含了当前访问数据,若有,则先将其移除,随后插入列表的最左侧。
移除命令
class redis.StrictRedis<---get_redis_connection返回该对象
lrem(name, count, value)----该函数的特点,当移除元素的时候,若该元素存在,则将其移除,否则什么都不做。因此不需要判断元素是否存在,直接进行移除操作即可
lpush(name, *values)---添加
ltrim(key, start, stop)---裁剪,只保留start和stop区间内的元素

# 获取用户购物车中商品的数目
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)
    

P63 获取同一SPU的其他规格的商品信息

在设计商品模块表格的时候,有SKU表还有SPU表【抽象出商品】    
获取跟这个商品同一个种类的其他规格的商品

# 获取同一个SPU的其他规格商品(写在购物车前面)
依旧从具体商品表中进行查询,为了防止重复查询,去除自身
same_spu_skus = GoodsSKU.objects.filter(goods=sku.goods).exclude(id=goods_id)

放进上下文context,传给模板
在detail.html页面中的数量下方进行显示,进行遍历显示

P65 商品列表内容的获取和显示

1.修改list.html模板
2.
定义视图类
class ListView(View):
    '''列表页'''
    def get(self, request):
        """显示列表页"""
        return render(request, 'list.html')


3.分析列表页面:
用户访问列表页面的时候,需要传给模板哪些信息
点种类的时候需要跳转到对应的列表页面
    1.需要显示是哪个种类的---种类id,同一种类的都需要展示出来
    2.要分页显示,需要告知是第几页---页码
    3.排序方式

4.设计列表页地址:
# 设计时遵循restful api----》
restful在设计的时候,地址遵循一定的设计格式,用户在访问一个浏览器地址的时候,其实是在请求一种资源。
比如:goods/1实际上就是请求id为1的商品,属于restful api设计的一种风格

/list?type_id=种类id&page=页码&sort=排序方式
/list/种类id/页码/排序方式
/list/种类id/页码?sort=排序方式《----这里选择这一种

跟在?后面的参数需要通过request.GET来获取,其余的参数需要在URL中进行捕获 

配置re_path(r'^list/(?P<type_id>\d+)/(?P<page>\d+)$', ListView.as_view(), name='list')

此时需要捕获其中的两个参数type_id和page

class ListView(View):
    '''列表页'''
    def get(self, request, type_id, page):
        """显示列表页"""
        # 先获取种类信息,如果用户查询的种类信息不存在,则跳转至商品首页
        try:
            type = GoodsType.object.get(id=type_id)
        except GoodsType.DoesNotExist:
            # 种类不存在
            return render(reverse("goods:index"))
        # 获取商品的分类信息
        types = GoodsType.objects.all()

        # 获取排序的方式 获取分类s商品的信息
        # 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')

        # 对数据进行分页
        # 


        return render(request, 'list.html')


此时分析列表页需要的数据:商品类型,分类商品展示,购物车信息,新品推荐

用户可以自己输入种类信息,这里进行参数校验,去数据库中查询是否有用户输入的数据信息
# 接下来获取分类商品的信息,从GoodsSKU表中查数据,此时商品需要按照某一信息进行排序,在查询之前需要获取排序方式

分页
Django文档中的Paginator类
from django.core.paginator import Paginator 

class Paginator(object_list, per_page)
object_list:列表元组,查询集等可以遍历的数据
per_page:每页显示多少条数据
用户传过来的page:用户要获取第几页的内容,用户传过来的参数要进行容错。传递过来的参数捕获之后是字符串,这里尝试将其转换为数字。
try...except...

属性:
Paginator.num_pages:分页之后页面的总页数
Paginator.page_range:分页之后页码的列表

方法:
Paginator.page(number):返回Page类的实例对象,在实例对象页中包含了当前页的数据

Page类中
属性:
Page.object_list:当前页上所有对象的列表
Page.paginator: 相关的paginator对象
page.paginator.page_range---即可获取到分页之后页码的列表
Page.number---page对象的属性,当前页的序号

方法:
Page.has_next():如果有下一页,则返回True
Page.has_previous():如果有上一页,则返回True


####################################################
# 对数据进行分页, Paginator(object_list, per_page)
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_authenicated():
    # 用户已登录
    conn = get_redis_connection('default')
    cart_key = "cart_%d" %(user.id)
    cart_count = conn.hlen(cart_key)

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

# 将context传给模板
###############################################################

<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 pageindex in skus_page.paginator.page_range %}
                {% if pageindex == skus_page.number %}
                    <a href="{% url 'goods:list' type.id pageindex %}?sort={{ sort }}" class="active">{{ pageindex }}</a>
                {% else %}
                    <a href="{% url 'goods:list' type.id pageindex %}?sort={{ sort }}">{{ pageindex }}</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>


# 在上一页或者下一页,要按照同样的排序方式显示,在传给模板数据的时候同样需要传入sort


当更换排序方式时,则将将其直接跳转到第一页
<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>

P64 列表页页码控制


最多显示五个页码,当前页,当前页的前两页和当前页的后两页

此时不能在列表页上直接遍历分页之后的完整页码列表,需要自己在views中生成一个页码列表

# todo: 进行页码的控制,页面上最多显示5个页码
case1: 总页数小于5页,页面上显示所有页码
case2: 如果当前页是前三页,显示1-5页
case3: 如果当前页是后三页,显示后5页
case4: 其他情况,显示当前页的前2页,当前页,当前页的后2页
num_pages = paginator.num_pages
if num_pages < 5:
    pages = range(1, num_pages + 1)
elif page < =3:
    pages = range(1, 6)
elif num_pages - page <= 2:
    pages = range(num_pages - 4, num_pages + 1)
else:
    pages = range(page - 2, page + 3)

# 将页码列表 传给模板,在模板中遍历自己生成的页码列表pages

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值