一、展示首页商品频道分类
1、首页商品频道分类数据结构分析
- 现在要将页面显示成类似上图;
- 数据展示的结构如下:(结构不是固定的,按项目需求而来)
(一张三级联动的表 是通过parent_id来做的)
{
"1":{
"channels":[
{
"id":1, "name":"手机", "url":"http://shouji.jd.com/"},
{
"id":2, "name":"相机", "url":"http://www.baidu.cn/"}
],
"sub_cats":[
{
"id":38,
"name":"手机通讯",
"sub_cats":[
{
"id":115, "name":"手机"},
{
"id":116, "name":"游戏手机"}
]
},
{
"id":39,
"name":"手机配件",
"sub_cats":[
{
"id":119, "name":"手机壳"},
{
"id":120, "name":"贴膜"}
]
}
]
},
"2":{
"channels":[],
"sub_cats":[]
}
}
- 这是一个json类型数据
- “1”:是组,共有11个
- “channels” 频道 一共是37个频道 下图频道展示了两个频道,频道下面还有二级“sub_cats”, "sub_cats"里面的"sub_cats"是一个三级分类,需要查询数据库,把数据拼接成下图结构给前端返回,前端接收到数据就可以显示到页面中来。
2、后端代码实现
- 定一个空的有序字典categories
- 查询所有的商品频道,按组号id 和 顺序号sequence 排序
- 对37个频道进行循环处理
- 取出组号
- 判断组号是否在categories中, 即是否登记过(37个频道只有11个组,频道会重复)
- 如果组id 不在 categories中,有序字典categories 增加一条记录,其中频道列表和sub_cats列表为空
- 根据频道对象获得对应的一级类别对象cat1
- 对有序字典categories的频道列表中添加频道信息
- 查询出cat1.id为parent_id的所有二级类别数据,并循环取出每一个二级类别对象cat2
- 将空列表赋值组cat2对象的sub_cat属性
- 对有序字典categories的sub_cats列表中添加频二级类别信息,并将cat2.sub_cat赋值给该对象的sub_cats
- 查询出cat2.id为parent_id的所有三级类别数据,并循环取出每一个三级类别对象cat3,并将cat3的信息组成的字典,添加到cat2.sub_cat列表中
- 至此,首页商品频道分类的json数据就已生成,将此数据按前端要求组成字典
- 返回首页html,带上商品频道分类的json数据(字典)
# apps/contents/views.py
from django.shortcuts import render
from django.views import View
from goods.models import GoodsCategory, GoodsChannel
from collections import OrderedDict
class IndexView(View):
"""首页广告"""
def get(self, request):
"""提供首页页面"""
# 查询并展示商品分类
# categories = {} # 优化 OrderedDict 由无序变成有序
categories = OrderedDict()
# 查询所有的商品频道
channels = GoodsChannel.objects.order_by('group_id', 'sequence')
for channel in channels:
# 37个频道 11个组
group_id = channel.group_id
# print(group_id)
if group_id not in categories:
categories[group_id] = {
'channels': [], 'sub_cats': []}
# print(categories)
cat1 = channel.category
categories[group_id]['channels'].append(
{
"id": cat1.id,
"name": cat1.name,
"url": channel.url
}
)
# print(categories) # 打印结果一级分类完成
# 查询二级和三级类别
# 查询二级 parent_id = cat1.id
# for cat2 in cat1.subs.all(): 此行简写代码可替换下面一行代码 models.py中定义了related_name=subs
for cat2 in GoodsCategory.objects.filter(parent_id=cat1.id).all():
cat2.sub_cats = []
categories[group_id]["sub_cats"].append(
{
"id": cat2.id,
"name": cat2.name,
"sub_cats": cat2.sub_cats
}
)
# for cat3 in cat2.subs.all():
for cat3 in GoodsCategory.objects.filter(parent_id=cat2.id).all():
cat2.sub_cats.append(
{
"id": cat3.id,
"name": cat3.name,
}
)
print(categories)
'''
{
"1":{
"channels":[
{"id":1, "name":"手机", "url":"http://shouji.jd.com/"},
{"id":2, "name":"相机", "url":"http://www.baidu.cn/"}
],
"sub_cats":[
{
"id":38,
"name":"手机通讯",
"sub_cats":[
{"id":115, "name":"手机"},
{"id":116, "name":"游戏手机"}
]
},
{
"id":39,
"name":"手机配件",
"sub_cats":[
{"id":119, "name":"手机壳"},
{"id":120, "name":"贴膜"}
]
}
]
},
'''
context = {
"categories": categories
}
return render(request, 'index.html', context=context)
3、前端页面实现
<ul class="sub_menu">
{
% for group in categories.values %}
<li>
<div class="level1">
{
% for channel in group.channels %}
<a href="{
{ channel.url }}">{
{
channel.name }}</a>
{
% endfor %}
</div>
<div class="level2">
{
% for cat2 in group.sub_cats %}
<div class="list_group">
<div class="group_name fl">{
{
cat2.name }} ></div>
<div class="group_detail fl">
{
% for cat3 in cat2.sub_cats %}
<a href="/list/{
{ cat3.id }}/1/">{
{
cat3.name }}</a>
{
% endfor %}
</div>
</div>
{
% endfor %}
</div>
</li>
{
% endfor %}
</ul>
二、查询所有的首页广告
- 数据库设计时,将首页广告分成不同类别,广告内容也统一格式存放
- 将所有广告按类别按格式发送组前端进行展示
1、首页广告数据结构分析
- 这是一个json的格式
- 以广告类别中key字段的值为字典的key,字典value 是 该类别广告内容组成的字典为元素的列表
- 如上图:index_lbt 是 广告类别表中 轮播图key字段的值
- 广告内容表中 美图 和 黑色星期五 的 类别id = 1
2、后端代码实现
- 查询所有广告类别
- 循环遍历所有广告类别
- 通过广告类别id查询该类别所有广告信息,排除不展示的,按显示顺序排序
- 用广告类别字段key的值为字典key,字典value为该类别所有广告信息字典组成的列表
- 将得到的字典按格式保存到前端数据集中
class IndexView(View):
"""商城首页"""
def get(self,request):
"""提供首页页面"""
# 查询并展示商品分类
......
# 查询所有的首页广告
# 查询所有广告类别
context_categories = ContentCategory.objects.all()
contents = {
}
for context_category in context_categories:
# temp1 = Content.objects.filter(category_id=context_category.id, status=True).all().order_by("sequence")
# print(type(temp1))
contents[context_category.key]=Content.objects.filter(category_id=context_category.id,status=True).all().order_by("sequence")
# print(contents)
context = {
"categories": categories,
'contents': contents,
}
return render(request, 'index.html', context=context)
3、前端页面实现
3.1 轮播图广告
<ul class="slide">
{% for content in contents.index_lbt %}
<li><a href="{
{ content.url }}"><img src="{
{ content.image }}" alt="{
{ content.title }}"></a></li>
{% endfor %}
</ul>
3.2 快讯和页头广告
<div class="news">
<div class="news_title">
<h3>快讯</h3>
<a href="#">更多 ></a>
</div>
<ul class="news_list">
{% for content in contents.index_kx %}
<li><a href="{
{ content.url }}">{
{ content.title }}</a></li>
{% endfor %}
</ul>
{% for content in contents.index_ytgg %}
<a href="{
{ content.url }}" class="advs"><img src="{
{ content.image }}"></a>
{% endfor %}
</div>
3.3 楼层广告(一楼)
<div class="list_model">
<div class="list_title clearfix">
<h3 class="fl" id="model01">1F 手机通讯</h3>
<div class="subtitle fr">
<a @mouseenter="f1_tab=1" :class="f1_tab===1?'active':''">时尚新品</a>
<a @mouseenter="f1_tab=2" :class="f1_tab===2?'active':''">畅想低价</a>
<a @mouseenter="f1_tab=3" :class="f1_tab===3?'active':''">手机配件</a>
</div>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl">
<img src="{
{ contents.index_1f_logo.0.image}}">
<div class="channel">
{% for content in contents.index_1f_pd %}
<a href="{
{ content.url }}">{
{ content.title }}</a>
{% endfor %}
</div>
<div class="key_words">
{% for content in contents.index_1f_bq %}
<a href="{
{ content.url }}">{
{ content.title }}</a>
{% endfor %}
</div>
</div>
<div class="goods_list_con">
<ul v-show="f1_tab===1" class="goods_list fl">
{% for content in contents.index_1f_ssxp %}
<li>
<a href="{
{ content.url }}" class="goods_pic"><img src="{
{ content.image }}"></a>
<h4><a href="{
{ content.url }}" title="{
{ content.title }}">{
{ content.title }}</a></h4>
<div class="price">{
{ content.text }}</div>
</li>
{% endfor %}
</ul>
<ul v-show="f1_tab===2" class="goods_list fl">
{% for content in contents.index_1f_cxdj %}
<li>
<a href="{
{ content.url }}" class="goods_pic"><img src="{
{ content.image }}"></a>
<h4><a href="{
{ content.url }}" title="{
{ content.title }}">{
{ content.title }}</a></h4>
<div class="price">{
{ content.text }}</div>
</li>
{% endfor %}
</ul>
<ul v-show="f1_tab===3" class="goods_list fl">
{% for content in contents.index_1f_sjpj %}
<li>
<a href="{
{ content.url }}" class="goods_pic"><img src="{
{ content.image }}"></a>
<h4><a href="{
{ content.url }}" title="{
{ content.title }}">{
{ content.title }}</a></h4>
<div class="price">{
{ content.text }}</div>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
3.4 楼层广告(二楼)
<div class="list_model model02">
<div class="list_title clearfix">
<h3 class="fl" id="model01">2F 电脑数码</h3>
<div class="subtitle fr">
<a @mouseenter="f2_tab=1" :class="f2_tab===1?'active':''">加价换购</a>
<a @mouseenter="f2_tab=2" :class="f2_tab===2?'active':''">畅享低价</a>
</div>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl">
<img src="{
{ contents.index_2f_logo.0.image}}">
<div class="channel">
{% for content in contents.index_2f_pd %}
<a href="{
{ content.url }}">{
{ content.title }}</a>
{% endfor %}
</div>
<div class="key_words">
{% for content in contents.index_2f_bq %}
<a href="{
{ content.url }}">{
{ content.title }}</a>
{% endfor %}
</div>
</div>
<div class="goods_list_con">
<ul v-show="f2_tab===1" class="goods_list fl">
{% for content in contents.index_2f_cxdj %}
<li>
<a href="{
{ content.url }}" class="goods_pic"><img src="{
{ content.image }}"></a>
<h4><a href="{
{ content.url }}" title="{
{ content.title }}">{
{ content.title }}</a></h4>
<div class="price">{
{ content.text }}</div>
</li>
{% endfor %}
</ul>
<ul v-show="f2_tab===2" class="goods_list fl">
{% for content in contents.index_2f_jjhg %}
<li>
<a href="{
{ content.url }}" class="goods_pic"><img src="{
{ content.image }}"></a>
<h4><a href="{
{ content.url }}" title="{
{ content.title }}">{
{ content.title }}</a></h4>
<div class="price">{
{ content.text }}</div>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
3.5 楼层广告(三楼)
<div class="list_model model03">
<div class="list_title clearfix">
<h3 class="fl" id="model01">3F 家居家装</h3>
<div class="subtitle fr">
<a @mouseenter="f3_tab=1" :class="f3_tab===1?'active':''">生活用品</a>
<a @mouseenter="f3_tab=2" :class="f3_tab===2?'active':''">厨房用品</a>
</div>
</div>
<div class="goods_con clearfix">
<div class="goods_banner fl">
<img src="{
{ contents.index_3f_logo.0.image }}">
<div class="channel">
{% for content in contents.index_3f_pd %}
<a href="{
{ content.url }}">{
{ content.title }}</a>
{% endfor %}
</div>
<div class="key_words">
{% for content in contents.index_3f_bq %}
<a href="{
{ content.url }}">{
{ content.title }}</a>
{% endfor %}
</div>
</div>
<div class="goods_list_con">
<ul v-show="f3_tab===1" class="goods_list fl">
{% for content in contents.index_3f_shyp %}
<li>
<a href="{
{ content.url }}" class="goods_pic"><img src="{
{ content.image }}"></a>
<h4><a href="{
{ content.url }}" title="{
{ content.title }}">{
{ content.title }}</a></h4>
<div class="price">{
{ content.text }}</div>
</li>
{% endfor %}
</ul>
<ul v-show="f3_tab===2" class="goods_list fl">
{% for content in contents.index_3f_cfyp %}
<li>
<a href="{
{ content.url }}" class="goods_pic"><img src="{
{ content.image }}"></a>
<h4><a href="{
{ content.url }}" title="{
{ content.title }}">{
{ content.title }}</a></h4>
<div class="price">{
{ content.text }}</div>
</li>
{% endfor %}
</ul>
</div>
</div>
</div>
4、功能完善
-
完成以上操作,页面图片不能打开:
-
结论:
- 通过FastDFS上传文件后返回的’Remote file_id’字段是文件索引。
- 文件索引会被我们存储到MySQL数据库。所以将来读取出来的也是文件索引,导致界面无法下载到图片。
-
解决方法:
- 重写Django文件存储类的url()方法。
- 在重写时拼接完整的图片下载地址(协议、IP、端口、文件索引)
- 详见《Django项目实践(商城):十四、补充:Django文件存储类url()》
- 切记,image后面加url