一、数据库中添加目录
(一)修改model
之前的数据库设计中没有考虑商品分类,所以需要新增一个Category的数据库。这个操作本来很简单,就是修改model,然后migrate即可。
但是由于原来数据库中已经存在了数据,所以我做migrate的时候,又提示什么字段不能使用默认值0,报了很多出错的信息,后来我直接将\coupon\migrations下面刚刚生成的py文件都删除了,再来做migrate,不过一下又说某个字段已经建立,一下又说Category表格已经存在,最后又出现如下错误:
django.db.utils.IntegrityError: (1452, 'Cannot add or update a child row: a fore
ign key constraint fails (`jd2`.`#sql-19fc_273`, CONSTRAINT `coupon_goods_catego
ry_id_15d33dd64cbe0dd0_fk_coupon_category_id` FOREIGN KEY (`category_id`) REFERE
NCES `coupon_category` (`id`))')
先不管它,继续。
2018-Aug-05 补记:
第二天给数据表添加新字段,执行python manage.py migrate还是出错,提示category已经存在,不能重复建立,我将建立category的sql命令删除,又提示不能resolve category,后来没办法,我只好将原先建立的数据表删除,然后将migrations文件夹下面,除了__init__.py之外的所有文件全部删除(__pycache__文件夹不要删除,不过里面的相关文件也要删除),

然后再重新执行makemigrations 和migrate命令。没想到还是出错:

后来问了别人,才知道要在数据库中,将migration表的相关记录也删除才行。就是下面这张表,找到app中名称 为你的app名称的记录,删除就可以了。

(二) save 和create
save的时候,建立用create
name = single['cidname'] cid = single['cid'] nameid = Category.objects.create(name=name,namecid=cid)

(三)foreign key的问题
后来我向商品数据表中的商品类别插入商品分类ID的时候,又出现了如下错误:
ValueError: Cannot assign "6144": "Goods.category" must be a "Category" instance.
在这里找到解决方案
you need to change your model structure, so you will be rather doing:
scripter = Scripter.objects.get(name="joshua") book = Book.objects.Create(script_title="some title",scripter=scripter)
按上面的方法修改,又出现了如下的错误:
coupon.models.MultipleObjectsReturned: get() returned more than one Category --
it returned 4!
原来是目录名称重复了,因为我是根据目录的id查找的,返回了4条目录的记录。
(四)文章表中存储文章分类
在文章数据表中,存储是商品分类的ID,我专门进后台发文章测试了一下。

二、修改首页逻辑
将views.py中首页的逻辑由函数改成class。
from django.views.generic import View
class IndexView(View):
"""
首页
"""
def get(self, request):
coupon_list = Goods.objects.all()
return render(request, 'coupon/index.html', {'coupon_list':coupon_list})
修改urls.py中的配置
url(r'^$', IndexView.as_view(), name='index'),
三、修改一个小按钮
仿的前端页面,有一个按钮,原来是红色的,到了我的网站就变成浅色了。

后来通过将style.css中的
background: url("pic/coupon-btn.png") no-repeat scroll 0 0;
直接改成:
background: #ED145B;
终于显示成红色了。或者直接改成red也行。
四、搜索功能
将category的代码改成以下这样:
def categorylist(request,c_id):
# 搜索功能
search_keywords = request.GET.get('keywords', '')
if search_keywords:
# icontains是包含的意思(不区分大小写)
categorylist = all_products.filter(name__icontains=search_keywords)
else:
categorylist = all_products.filter(category_id=c_id)
return render(request, 'coupon/category.html', {'categorylist': categorylist})
再在urls.py中,将原来的代码
url(r'^category/(?P<c_id>\d+)/$',views.categorylist),
改成:
url(r'^category/(.*)',views.categorylist),
然后在模板文件中,将搜索的链接改成
<a href="category/?keywords=秋装" target="_blank">
就可以了。这样不论是点击搜索,还是点击文章的目录,都可以正常跳转了。
五、顶部搜索框
原来想用JS来解决,可是用的别人的JS的代码,有各种问题,包括:
1、在首页可以搜索,在商品详情页、列表页无法搜索。
2、在chrome、IE浏览器下面可以正常搜索,在firefox浏览器下无法使用,点击搜索出现出错页面。
3、修改代码后,在IE浏览器下,跳转网址中出现已经注释过的代码中的跳转网址。
最后,不使用JS,AJAX,直接使用django内置功能完成搜索功能,目前只搜索商品标题。当然,以后有需要,可以使用django-haystack,它支持全文检索、按搜索相关度排序、关键字高亮等功能。
前端测试代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.bootcss.com/ionicons/2.0.1/css/ionicons.min.css">
</head>
<body>
<form role="search" method="get" id="searchform" action="{% url 'coupon:search' %}">
<input type="search" name="q" placeholder="搜索" required>
<button type="submit"><span class="ion-ios-search-strong"></span></button>
</form>
</body>
</html>
它是长成这样的:

views.py的代码:
def search(request):
q = request.GET.get('q')
error_msg = ''
if not q:
error_msg = '请输入关键词'
return render(request, 'coupon/category.html', {'error_msg': error_msg})
else:
categorylist = all_products.filter(name__icontains=q)
return render(request, 'coupon/category.html', {'error_msg': error_msg,
'categorylist': categorylist})
urls.py的代码:
url(r'^search/$', views.search, name='search'),
经测试,在各个页面均测试正常。
六、json loads错误问题
今天执行获取百度相关词的时候,出错了如下的错误:
json.decoder.JSONDecodeError: Invalid \escape: line 1 column 900 (char 899)
经过排查,是某字段中含有“\”符号,导致json loads的时候出错。

于是加了一段代码,直接将“\”给替换掉,暂时解决。
content = content.replace('\\', '')
七、分页功能
使用的是django pure pagination,差一点就没有调试成功了。
其实也很简单,先pip安装,然后在settings.py中添加INSTALLED_APPS,然后再修改views.py
def categorylist(request,c_id):
#产品列表页
list_categories = all_categories
list_product = all_products
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# Provide Paginator with the request object for complete querystring generation
p = Paginator(list_product,16, request=request) #这个list_product是全部的商品
products = p.page(page) #这个products是传到列表页的
return render(request, 'coupon/category.html', {'products': products,
'list_categories':list_categories
})
最开始的时候,我的这行代码'products': products,写成了'list_product': products,结果前端显示不出来。
然后在前端的页面中,需要这样调用:
{% for categoryproduct in products.object_list %}
因为前面传过来的是products,所以这里直接抄这行代码就可以了。
然后就是修改下面的分页按钮,结果将代码copy到我的模板文件,浏览时报错:
Exception Value: Invalid block tag: 'trans', expected 'elif', 'else' or 'endif'
原来是要加上{% load i18n %}这段代码才行。
最后没搞出来,直接拿别人的来用了(只要views传过来是products,这里的代码什么都不用改):
<div class="pageturn">
<ul class="pagelist">
{% if products.has_previous %}
<li class="long"><a href="?{{ products.previous_page_number.querystring }}" >上一页</a></li>
{% endif %}
{% for page in products.pages %}
{% if page %}
{% ifequal page products.number %}
<li class="active"><a href="?{{ page.querystring }}">{{ page }}</a></li>
{% else %}
<li><a href="?{{ page.querystring }}">{{ page }}</a></li>
{% endifequal %}
{% else %}
<li class="none"><a href="">...</a></li>
{% endif %}
{% endfor %}
{% if products.has_next %}
<li class="long"><a href="?{{ products.next_page_number.querystring }}">下一页</a></li>
{% endif %}
</ul>
</div>
相应的css代码:
.pageturn {
clear: both;
height: 30px;
margin: 50px auto;
display: table;
text-align: center;
}
.pageturn .pagelist {
display: table-cell;
vertical-align: middle;
overflow: hidden;
}
.pageturn li {
width: 30px;
height: 30px;
line-height: 30px;
margin-left: 10px;
float: left;
text-align: center;
}
.pageturn li:first-child {
margin-left: 0;
}
.pageturn li:hover a, .pageturn .active a {
background: #f5114a;
color: #fff;
border-color: #eaeaea;
}
.pageturn a {
border: 1px solid #eaeaea;
display: block;
height: 28px;
color: #6c6c6c;
}
.pageturn .long {
width: 100px;
}
.pageturn .none a {
border: 0;
}
.pageright {
float: right;
width: auto;
display: inline;
clear: none;
margin-top: 10px;
}
2018-Aug-12:
今天终于将此网站全部开发完成,可以布署上线了。
八、优化搜索页面
搜索页面是套用的产品列表页,搜索结果中也会显示这样的东西:

这里的链接又是根据某一目录排序的,这样对搜索结果其实是不适用的,因为根据某一产品关键字搜索出来的东西很可能属于不同的分类。所以通过以下代码将这部分内容在搜索结果页面隐藏:
{% ifequal display 1 %}
<a href="/category/{{c_id}}_1/">
<li class="yes">券后价最低</li>
</a>
<a href="/category/{{c_id}}_2/">
<li class="yes">优惠最多</li>
</a>
<a href="/category/{{c_id}}_3/">
<li class="yes">销量</li>
</a>
{% endifequal %}
即在列表页传一个display=1的参数,这个参数等于1的时候,才会显示if代码块中包含的内容,这样就达到了在搜索结果页面隐藏这部分内容的目的。
九、优化产品列表页面
原来的www.xx.com/list/和www.xx.com/list/1/写了两个函数,而且配置了两条url。
url(r'^category/(?P<c_id>\d+)/$',views.listdetail),
url(r'^category/(.*)',views.categorylist),
views.py
def categorylist(request,c_id):
#产品列表页
list_categories = all_categories
list_product = all_products
sort = request.GET.get('sort', "")
if sort:
if sort == "price":
list_product = all_products.order_by("coupon_price")
elif sort == "99":
list_product = all_products.filter(coupon_price__lte=20)
elif sort == "sales":
list_product = sale_product
else:
sort == "coupon"
list_product = all_products.order_by("-coupon_amount")
#分页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
# Provide Paginator with the request object for complete querystring generation
p = Paginator(list_product,16, request=request)
products = p.page(page)
return render(request, 'coupon/category.html', {'products': products,
'list_categories':list_categories
})
def listdetail(request,c_id):
#带分类ID的列表页
list_categories = all_categories[:14]
#通过分类ID取得该分类下的所有产品
list_product = all_products.filter(category_id=int(c_id)).order_by('-add_time')
sort = request.GET.get('sort', "")
if sort:
if sort == "price":
list_product = list_product.order_by("coupon_price")
elif sort == "sales":
list_product = list_product.order_by("sale_amount")
else:
sort == "coupon"
list_product = list_product.order_by("-coupon_amount")
#分页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
p = Paginator(list_product, 16, request=request)
products = p.page(page)
return render(request, 'coupon/category.html', {'products': products,
'list_categories':list_categories
})
今天将它优化了一下,合并成了一个函数。
def categorylist(request,c_id,sort):
"""
产品列表页
"""
list_categories = all_categories
display = 1
#设定一个变量,控制相关html的显示
if c_id == "0":
#直接list列表,不带分类ID
if sort == "0":
#默认按时间排序
list_product = all_products
elif sort == "1":
#按券后价最低排序
list_product = all_products.order_by("coupon_price")
elif sort == "2":
#按优惠最多排序
list_product = all_products.order_by("-coupon_amount")
elif sort == "3":
#按销量排序排序
list_product = all_products.order_by("-sale_amount")
else:
return render(request, 'coupon/404.html')
else:
#带分类ID的列表页
list_categories = all_categories[:14]
list_product = all_products.filter(category_id=int(c_id)).order_by('-add_time')
if sort == "0":
pass
elif sort == "1":
list_product = list_product.order_by("coupon_price")
elif sort == "2":
list_product = list_product.order_by("-coupon_amount")
elif sort == "3":
list_product = list_product.order_by("-sale_amount")
else:
return render(request, 'coupon/404.html')
# 分页
try:
page = request.GET.get('page', 1)
except PageNotAnInteger:
page = 1
p = Paginator(list_product, 16, request=request)
products = p.page(page)
return render(request, 'coupon/category.html', {'products': products,
'list_categories': list_categories,
'c_id':c_id,
'display':display
})