图书推荐系统(七)之应用配置rank
1、url配置
在rank
目录添加urls.py
from django.conf.urls import url
from rank.views import score,tag,all
urlpatterns = [
url(r'^score/$', score),
url(r'^tag/$', tag),
url(r'all/$',all),
]
2、index应用目录结构
├── index
│ ├── __init__.py # 配置应用
│ ├── admin.py # 提供django.contrib.admin 模块管理我们创建的数据模型
│ ├── apps.py
│ ├── migrations # 是一个文件夹,用于数据模型与数据库结构的同步
│ ├── models.py # 用于定义数据模型
│ ├── tests.py # 供单元测试使用
│ └── views.py # 是写主要的业务逻辑的地方
│ └── urls.py
3、视图和模板
分为三个模块,分别是高分榜、标签榜单、所有图书。 首先用户登录,将用户名写入session,若未登录,则跳转到登录界面login.html (1)高分榜 @views.py
1)从数据库Book表筛选出评分高于9.5的前100本图书,逆序排列; 2)分页,每页展示20条内容 3)传参到rank.html
def score(request):
# 登录是将用户写入session,此时若获取不到,则返回错误
username = request.COOKIES.get('name')
# 如果用户未登录
if not username:
return render_to_response('login.html',{
'error':'用户未登录,请先登录!',
'user_name':"",
'user_pwd':"",
})
# 筛选出评分高于9.5的前100本图书,"-bookscore"表示逆序
books = Book.objects.filter(bookscore__gt=9.5).order_by("-bookscore")[:100]
# 分页,每页展示20条内容
paginator = Paginator(books, 20)
#寻找名为page的GET参数
page = request.GET.get('page')
try:
new_book = paginator.page(page)
except PageNotAnInteger:
# 若页数不是整数,转向第一页
new_book = paginator.page(1)
except EmptyPage:
# 若页数超出范围了,转向结果最后一页,paginator.num_pages表示页面总数
new_book = paginator.page(paginator.num_pages)
return render_to_response("rank.html",{
"user_name":username,
"books":new_book,
"type":1,
"len_list":range(1,paginator.num_pages + 1),
})
@rank.html 1)设置表头 2)从views.py获取books,采用for循环传递图书信息 3)采用Django自带的Paginator分页工具。 补充:Paginator分页步骤: 获取要展示的对象列表,将列表和每页个数传递给Paginator,返回一个分页对象,调用该对象的各种方法,获取各种分页信息,在HTML模板中,使用上面的分页信息构建分页栏。
<!--高分榜-->
{% ifequal type 1 %}
<ul class="rankcan">
<li class="recomtitle">
<span>封面</span>
<div>
<span>书名</span>
<span>综合评分</span>
<span>查看详情</span>
<span>相关标签</span>
</div>
</li>
<!--数据循环部分-->
{% for book in books %}
<li class="recomitem">
<img src="/static/bookimg/{{ book.bookid }}.jpg">
<div>
<span>{{ book.bookname }}</span>
<span>{{ book.bookscore }}</span>
<span><a href="https://book.douban.com/subject/{{ book.bookid }}" target="_blank">查看详情</a></span>
<span class="sign">
{% for tag in book.tag_split %}
<a class="badge badge-default">{{ tag }}</a>
{% endfor %}
</span>
</div>
</li>
{% endfor %}
<!--数据循环部分end-->
</ul>
<!--翻页-->
<div class="eassy-page pagen">
<ul class="pagination page-list">
<li class="previous">
{% if books.has_previous %}
<a href="?page={{ books.previous_page_number }}"><span>«</span></a>
{% else %}
<a><span>«</span></a>
{% endif %}
</li>
{% for page in len_list %}
<li><a href="?page={{ page }}"></a></li>
{% endfor %}
<li class="next">
{% if books.has_next %}
<a href="?page={{ books.next_page_number }}"><span>»</span></a>
{% else %}
<a><span>»</span></a>
{% endif %}
</li>
</ul>
</div>
{% endifequal %}
<!--高分榜end-->
(2)标签榜 1)加载离线计算好的标签榜单文件,排序 2)传递参数到rank.html @views.py
def tag(request):
# 登陆是将用户写入session,此时若获取不到,则返回错误
username = request.COOKIES.get('name')
# 如果用户为登陆
if not username:
return render_to_response('login.html', {
'error': "用户未登陆,请先登陆!",
'user_name': "",
'user_pwd': ""
})
# 加载离线计算好的标签榜单
if os.path.exists(tags_path):
tags_dict = dict(json.load(open(tags_path,"r")))
else:
print("标签统计结果文件不存在,请检查!")
new_tags_sorted_dict = sorted(tags_dict.items(),key=lambda k:k[1], reverse=True)
return render_to_response("rank.html",{
"user_name":username,
"tags":new_tags_sorted_dict,
"type":2
})
@rank.html
<!--标签云-->
{% ifequal type 2 %}
<div class="signcan">
<!--数据循环部分-->
{% for key,value in tags %}
<div>
<a href="/rank/all/?tag={{ key }}"><span class="badge badge-info">{{ key }}:{{ value }}次</span></a>
</div>
{% endfor %}
<!--数据循环部分end-->
</div>
{% endifequal %}
<!--标签云end-->
(3)所有图书 1)采用两种方法,一个是post,一个是get,post需要自己填写信息,get直接获取信息 2)若采用post,从数据库Book表中筛选标签和评分限制,根据评分逆序排列;若采用get,设置默认评分限制,从数据库Book表中筛选标签,根据评分逆序排列 3)分页 4)返回rank.html和参数 @views.py
def all(request):
# 登陆是将用户写入session,此时若获取不到,则返回错误
username = request.COOKIES.get('name')
# 如果用户为登陆
if not username:
return render_to_response('login.html', {
'error': "用户未登陆,请先登陆!",
'user_name': "",
'user_pwd': ""
})
# 如果是查询某个标签下的数据
# post需要提交信息,这里自己填写评分限制和标签;get直接获取信息,评分限制默认为0和10,需自己填写标签
if request.method == "POST":
tag_temp = request.POST.get("tag")
tag = tag_temp if tag_temp else "电影"
low = request.POST.get("lowfen")
lowfen = float(low) if low else 0.0
high = request.POST.get("highfen")
highfen = float(high) if high else 10.0
books = Book.objects.filter(booktag__icontains=tag).filter(bookscore__range=(lowfen,highfen)).order_by("-bookscore")
# 如果get请求
else:
lowfen = "0"
highfen = "10"
get_tag = request.GET.get('tag')
if get_tag:
tag = get_tag
books = Book.objects.filter(booktag__icontains=tag).order_by("-bookscore")
elif not get_tag:
tag = "电影"
books = Book.objects.order_by("-bookscore")
paginator = Paginator(books, 20)
page = request.GET.get('page')
try:
new_book = paginator.page(page)
except PageNotAnInteger:
new_book = paginator.page(1)
except EmptyPage:
new_book = paginator.page(paginator.num_pages)
return render_to_response("rank.html",{
"user_name":username,
"books":new_book,
"type":3,
"tag":tag,
"lowfen":lowfen,
"highfen":highfen,
"len_list":paginator.num_pages + 1,
})
@rank.html html中name 属性用于对提交到服务器后的表单数据进行标识,或者在客户端通过 JavaScript 引用表单数据。 1)拿到book变量,获取图书信息 2)“我要评分”:bootstrap框架的data-toggle指以什么事件触发,常用的如modal,popover,tooltips等,data-target指事件的目标,这里是指#{{ book.bookid }}这个Dom元素的内容以模态框的形式展示。
<!--所有图书-->
{% ifequal type 3 %}
<div class="rankcan">
<div class="rank_all_form">
<form class="form-inline" role="form" method="post" action="/rank/all/">
<div class="form-group">
<span>输入标签 :</span>
</div>
<div class="form-group">
<div class="col-sm-10" style="display:inline;">
<input type="text" class="form-control" name="tag" id="sign" value="{{ tag }}">
</div>
</div>
<div class="form-group">
<span>查询最低分 :</span>
</div>
<div class="form-group">
<div class="col-sm-10">
<input type="text" class="form-control" name="lowfen" id="lowfen" value="{{ lowfen }}">
</div>
</div>
<div class="form-group">
<span>查询最高分 :</span>
</div>
<div class="form-group">
<div class="col-sm-10">
<input type="text" class="form-control" name="highfen" id="highfen" value="{{ highfen }}">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">搜索</button>
</div>
</div>
</form>
</div>
<br/>
<hr class="rank_all_form">
<ul>
<li class="recomtitle">
<span>封面</span>
<div class="sixta">
<span>书名</span>
<span>综合评分</span>
<span>相关标签</span>
<span>查看详情</span>
<span>我要评分</span>
</div>
</li>
<!--数据循环部分-->
{% for book in books %}
<li class="recomitem">
<img src="/static/bookimg/{{ book.bookid }}.jpg">
<div class="sixta">
<span>{{ book.bookname }}</span>
<span>{{ book.bookscore }}</span>
<span class="sign">
{% for tag in book.tag_split %}
<a class="badge badge-default">{{ tag }}</a>
{% endfor %}
</span>
<span><a href="https://book.douban.com/subject/{{ book.bookid }}" target="_blank">查看详情</a></span>
<span class="fenbtn" data-toggle="modal" data-target="#{{ book.bookid }}">我要评分</span>
</div>
</li>
<div class="modal fade" id="{{ book.id }}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="myModalLabel">我要评分</h4>
</div>
<div class="modal-body">
<form role="form" method="post" action="/user/action/">
<div class="form-group">
<label for="name">图书iD</label>
<input type="text" class="form-control" disabled value="{{ book.bookid }}">
<input type="hidden" class="form-control" id="bookid" name="bookid" value="{{ book.bookname }}">
</div>
<div class="form-group">
<label for="name">书名</label>
<input type="text" class="form-control" id="bookname" name="bookname" disabled value="{{ book.bookname }}">
</div>
<div class="form-group">
<label for="name">评分</label>
<input type="text" class="form-control" id="bookscore" name="bookscore" placeholder="请输入评分">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
<button type="submit" class="btn btn-primary">提交</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endfor %}
<!--数据循环部分end-->
</ul>
</div>
<div class="eassy-page pagan">
<ul class="pagination page-list page-listli">
<li class="previous">
{% if books.has_previous %}
<a href="?page={{ books.previous_page_number }}&tag={{ tag }}"><span>上一页</span></a>
{% else %}
<a><span>上一页</span></a>
{% endif %}
</li>
<div class="form-group jump">
<span for="name">输入页数(共:{{ len_list }}页)</span>
<input type="text" class="form-control" id="pageid" name="pageid">
<button type="button" class="btn btn-primary" onclick="transform()">跳转</button>
</div>
<li class="next">
{% if books.has_next %}
<a href="?page={{ books.next_page_number }}&tag={{ tag }}"><span>下一页</span></a>
{% else %}
<a><span>下一页</span></a>
</li>
</ul>
</div>
{% endifequal %}
<!--所有图书end-->
# 跳转
<script language="javascript" type="text/javascript">
function transform() {
var page = document.getElementById('pageid').value;
location.href = "/rank/all/?page="+page;
}
</script>