零基础使用Django2.0.1打造在线教育网站(十六):列表分页功能

关于博主

努力与运动兼备~~~有任何问题可以加我好友或者关注微信公众号,欢迎交流,我们一起进步!

                 微信公众号:  啃饼思录
                 QQ: 2810706745(啃饼小白)

写在前面

本篇笔记我们将介绍列表分页,分类筛选,课程机构排序以及学习人数和课程人数排名等功能的实现。

本篇笔记对应于第十六篇代码,对应于github的位置是https://github.com/licheetools/eduline

列表分页

各位小伙伴们看下面的图片,这就是列表分页,怎么样是不是觉得很简单,其实它挺复杂的,下面介绍如何实现这个功能:

我们是通过django-pure-pagination这个库来实现的,所以首先进入到我们的虚拟环境,安装这个库:

C:\Users\YC>F:

F:\>cd envs

F:\Envs>cd eduline

F:\Envs\eduline>workon eduline
(eduline) F:\Envs\eduline>pip install django-pure-pagination -i https://pypi.tuna.tsinghua.edu.cn/simple
Collecting django-pure-pagination
Installing collected packages: django-pure-pagination
Successfully installed django-pure-pagination-0.3.0

(eduline) F:\Envs\eduline>

然后去settings.py文件里,注册这个app:

'pure_pagination',

接下来点击github上的项目地址django-pure-pagination,然后下拉至settings:

我们看一下可设置的参数:

PAGINATION_SETTINGS = {
    'PAGE_RANGE_DISPLAYED': 10,
    'MARGIN_PAGES_DISPLAYED': 2,

    'SHOW_FIRST_PAGE_WHEN_INVALID': True,
}

解释一下上面参数的意义:

PAGE_RANGE_DISPLAYED:  表示总共会显示多少个页数。(包括省略号,两边和中间)
MARGIN_PAGES_DISPLAYED:  表示旁边会显示多少个。
SHOW_FIRST_PAGE_WHEN_INVALID:  表示当输入页数不合法是否要跳到第一页

我们继续下拉,看一下官方给的例子:

# views.py
from django.shortcuts import render_to_response

from pure_pagination import Paginator, EmptyPage, PageNotAnInteger


def index(request):
    # 尝试获取页数参数
    try:
        page = request.GET.get('page', 1)
    except PageNotAnInteger:
        page = 1
    # objects是取到的数据
    objects = ['john', 'edward', 'josh', 'frank']

    # 对取到的数据进行分页
    p = Paginator(objects, request=request)
    # 此时前台显示的就是我们此前获取的第几页的数据
    people = p.page(page)

    return render_to_response('index.html', {
        'people': people,
    }

我们尝试对照实现:

# 课程机构列表功能
class OrgView(View):
    def get(self, request):
        # 查找所有的城市信息
        all_citys = CityDict.objects.all()
        # 查找所有的课程机构信息
        all_orgs = CourseOrg.objects.all()
        # 统计课程机构的数量
        org_nums = all_orgs.count()
        # 对课程机构进行分页,尝试获取前端get请求传递过来的page参数
        # 如果是不合法的配置参数则默认返回第一页
        try:
            page = request.GET.get('page', 1)
        except PageNotAnInteger:
            page = 1
        # 这里指从all_org中取五个出来,每页显示6个,这个字段必填
        p = Paginator(all_orgs, 6, request=request)

        orgs = p.page(page)

        return render(request, "org-list.html", {
            "all_citys": all_citys,
            "all_orgs": orgs,
            "org_nums": org_nums,
        })
继续看我们的官方文档:

我们知道,因为我们返回给后端的是QueryDict,所以在前端页面可以使用for循环进行遍历显示,但是这里的orgs却不一定可以,查看文档,果真不能那样遍历,而是遍历其object_list,这一点很容易出错,需要格外注意。我们在前端页面配置如下:

{% for course_org in all_orgs.object_list %}
也就是这个地方:

现在考虑如何在前端页面显示分页:

如果使用默认的render:

前端页面配置如下:

运行项目结果:

这有点丑,所以我们还是自定义html页面的代码吧!怎么定义呢,还是查阅官方文档吧!

往下拉,可以看到这段代码,这就是官方文档告诉我们如何自定义分页样式的:

{% load i18n %}
<div class="pagination">
    {% if page_obj.has_previous %}
        <a href="?{{ page_obj.previous_page_number.querystring }}" class="prev">&lsaquo;&lsaquo; {% trans "previous" %}</a>
    {% else %}
        <span class="disabled prev">&lsaquo;&lsaquo; {% trans "previous" %}</span>
    {% endif %}
    {% for page in page_obj.pages %}
        {% if page %}
            {% ifequal page page_obj.number %}
                <span class="current page">{{ page }}</span>
            {% else %}
                <a href="?{{ page.querystring }}" class="page">{{ page }}</a>
            {% endifequal %}
        {% else %}
            ...
        {% endif %}
    {% endfor %}
    {% if page_obj.has_next %}
        <a href="?{{ page_obj.next_page_number.querystring }}" class="next">{% trans "next" %} &rsaquo;&rsaquo;</a>
    {% else %}
        <span class="disabled next">{% trans "next" %} &rsaquo;&rsaquo;</span>
    {% endif %}
</div>

注意:这里面的page_obj其实就是我们的all_orgs!

下面我们继续尝试对照实现,打开org-list.html页面,找到对应位置,复制官方文档内容,然后进行替换(代码格式化ctrl+alt+L):

 <div class="pageturn">
                <ul class="pagelist">
                    {% if all_orgs.has_previous %}
                        <li class="long"><a href="?{{ all_orgs.previous_page_number.querystring }}">上一页</a></li>
                    {% endif %}
                    {% for page in all_orgs.pages %}
                        {% if page %}
                            {% ifequal page all_orgs.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 all_orgs.has_next %}
                        <li class="long"><a href="?{{ all_orgs.next_page_number.querystring }}">下一页</a></li>
                    {% endif %}
                </ul>
            </div>
就是这个样子:

刷新一下我们的页面,出现了分页:

因为只有10个课程机构,每页只显示6个所以最多只有2页!

城市分类的筛选

首先打开我们的organization/views.py文件,在里面添加如下数据:

city_id = request.GET.get('city', '')
        # 选中了某个城市之后,根据城市Id与数据库中的city_id进行判断(外键city在数据库中名为city_id且为字符串类型)
        if city_id:
            all_orgs = all_orgs.filter(city_id=int(city_id))

return render(request, "org-list.html", {
            "city_id": city_id,
        })
就是这个样子:

然后打开org-list.html页面,我们需要回传我们的city_id并加以显示出来:

<div class="cont">
          <a href="?ct="><span class="{% ifequal city_id '' %}active2{% endifequal %}">全部</span></a>   # 判断是否选择城市,如果没有则显示全部,并显示加绿状态
           {% for city in all_citys %}
           <a href="?city={{ city.id }}"><span class="{% ifequal city_id city.id|stringformat:"i" %}active2{% endifequal %}">{{ city.name }}</span></a> # 判断是否选择城市并显示加绿状态
           {% endfor %}
</div>

解释一下这行代码的意思:

class="{% ifequal city_id city.id|stringformat:"i" %}active2{% endifequal %}"

这行代码的意思是说,如果所选城市的city_id与数据库中的city_id(其实就是city,不过在数据库中自动变成了字符串类型的city_id)相等,就是选择了当前城市,并且为加绿状态。city.id|stringformat:"i"就是把数据库中的字符串类型的city_id转换成整型值并加以比对,此处city.id中的id对象其实就是刚才转换成的整型值!

变成了这个样子:

你可以刷新一下页面后,切换几个城市试试看,没有问题的!接下来我们仿照上面的操作,对机构的类别也进行一下分类筛选。

机构类别的筛选

首先打开我们的organization/views.py文件,在里面添加如下数据:

# 机构类别的筛选
# ct是我们前端页面用于判断机构类别用的
category = request.GET.get('ct', '')
# 选中了类别之后,根据category与数据库中的category进行判断,从而显示授课机构
 if category:
    all_orgs = all_orgs.filter(category=category)

return render(request, "org-list.html", {
            "category": category,
        })
就是这个样子:

然后打开org-list.html页面,我们需要回传我们的category并加以显示出来:

<div class="cont">
<a href="?city="><span class="{% ifequal category '' %}active2{% endifequal %}">全部</span></a>

<a href="?ct=pxjg&city="><span class="{% ifequal category 'pxjg' %}active2{% endifequal %}">培训机构</span></a>
 <a href="?ct=gx&city="><span class="{% ifequal category 'gx' %}active2{% endifequal %}">高校</span></a>

 <a href="?ct=gr&city="><span class="{% ifequal category 'gr' %}active2{% endifequal %}">个人</span></a>
</div>
也就是这个样子:

然后去数据库里修改几个课程机构的类别,便于我们后续的进行:

不过这样还是不行的,我们需要对城市信息与机构分类进行联动,也就是说可以进行二次选择,可以选择所有在北京市的培训机构,而不是只能显示全北京市的机构(包括培训机构,个人和高校),下面我们在org-list.html页面进行修改代码:

 <a href="?city={{ city_id }}"><span
    class="{% ifequal category '' %}active2{% endifequal %}">全部</span></a>

     <a href="?ct=pxjg&city={{ city_id }}"><span
      class="{% ifequal category 'pxjg' %}active2{% endifequal %}">培训机构</span></a>

<a href="?ct=gx&city={{ city_id }}"><span
   class="{% ifequal category 'gx' %}active2{% endifequal %}">高校</span></a>

 <a href="?ct=gr&city={{ city_id }}"><span
class="{% ifequal category 'gr' %}active2{% endifequal %}">个人</span></a>


<a href="?ct={{ category }}"><span class="{% ifequal city_id '' %}active2{% endifequal %}">全部</span></a>
   {% for city in all_citys %}
    <a href="?city={{ city.id }}&ct={{ category }}"><span class="{% ifequal city_id city.id|stringformat:"i" %}active2{% endifequal %}">{{ city.name }}</span></a>
  {% endfor %}
也就是这个样子:

我们刷新一下我们的页面,可以发现已经可以联动了:

不过右边的机构数量统计错了,我们刚才统计机构数目过早,应该移到后面,在已经筛选过后,才能开始统计,所以只需要把刚才用于统计的那行代码挪到筛选代码的后面即可:

# 统计课程机构的数量
org_nums = all_orgs.count()
就是这样:

再来刷新一下我们的页面,发现课程机构数量统计没有问题!

授课机构排名

授课机构排名就是图片中右边的那个,我们根据课程机构的点击数来进行排名:

首先打开我们的organization/views.py文件,在里面添加如下数据:

 # 授课机构的排名
        hot_orgs = all_orgs.order_by("click_nums")[:3]  # 返回的是一个QueryDict我们取前三个

然后我们在org-list.html页面进行修改代码:

<div class="right companyrank layout">
            <div class="head">授课机构排名</div>

            {% for current_org in hot_orgs %}
                <dl class="des">
                    <dt class="num fl">{{ forloop.counter }}</dt>
                    <dd>
                        <a href="/company/2/"><h1>{{ current_org.name }}</h1></a>
                        <p>{{ current_org.address }}</p>
                    </dd>
                </dl>
            {% endfor %}
        </div>

其中{{ forloop.counter }}是Django内置的用于统计循环变量循环到第几次的次数。

完成以后,我们再来刷新一下我们的页面,发现授课机构排名没有问题!

学习人数和课程人数排名

其实这个功能和前面介绍的几个功能很相似,这里就简单介绍一下(步骤和前面的类似)

首先打开我们的organization/views.py文件,在里面添加如下数据:

 # 学习人数和课程人数排名
        sort = request.GET.get('sort', '')
        if sort:
            if sort == "students":
                all_orgs = all_orgs.order_by("-students")
            elif sort == "courses":
                all_orgs = all_orgs.order_by("-course_nums")

return render(request, "org-list.html", {
            "sort": sort,
        })

然后我们在org-list.html页面进行修改代码:

<ul class="tab_header">
<li class="{% if sort == '' %}active{% endif %}"><a href="?ct={{ category }}&city={{ city_id }}">全部</a> </li>
<li class="{% if sort == 'students' %}active{% endif %}"><a href="?sort=students&ct={{ category }}&city={{ city_id }}">学习人数 &#8595;</a></li>
<li class="{% if sort == 'courses' %}active{% endif %}"><a href="?sort=courses&ct={{ category }}&city={{ city_id }}">课程数 &#8595;</a></li>
</ul>

sort=students&ct={{ category }}&city={{ city_id }}sort=courses&ct={{ category }}&city={{ city_id }}也是为了和前面的保持联动状态。

完成以后刷新一下我们的页面,看上面的各个功能是不是都实现了。

至此本篇关于列表分页,分类筛选,课程机构排序以及学习人数和课程人数排名等功能的介绍就到此为止了,感谢你的赏阅。

本篇笔记对应于第十六篇代码,对应于github的位置是https://github.com/licheetools/eduline

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏BIT泽清

教你如何提审iOS马甲包不会遇到2.1大礼包或4.3正确姿势分享

App Store 搜索关键词 世界杯 或者 通过链接下载 皇冠Ьet365-世界杯体育赛事直播吧:https://itunes.apple.com/cn/ap...

90250
来自专栏小文博客

良心压缩软件Bandizip——无广告超精简

9.6K50
来自专栏令仔很忙

新手学HighCharts(一)----基本使用

最近做的项目需要用到数据分析,图表显示,之前做项目的时候用到过highcharts,不过也只是简单的会用而已,然后再网上查了查highcharts的优点:

16510
来自专栏吉浦迅科技

【阿星的学习笔记(1)】如何在windows安裝Theano +Keras +Tensorflow並使用GPU加速訓練神經網路

今天开始,Lady向各位介绍一个朋友阿星(Ashing)以及他的机器学习读书笔记! ? 阿星也是我们手撕深度学习算法微信群的热心群友!接下来,Lady我也会陆续...

47760
来自专栏FreeBuf

新年伊始,Java惊爆首个0day

日前,Java又爆了一个新的0day,可能让攻击者获取计算机管理权限,Java 7 Update 10或更早的版本中存在该漏洞,该漏洞可以允许未经身份验证的远程...

20960
来自专栏技术总结

Python爬取电影天堂

摘取部分网友的回复: 1、之前在北京买房,谁想房价开始疯长,链家的房价等数据分析只给了一小部分,远远不能满足自己的需求。于是晚上花了几个小时的时间写了个爬虫,...

21930
来自专栏Python中文社区

怎样用Python实现地理编码

怎样用Python实现地理编码 专栏作者:时空Drei ❈ 时空Drei,德国德累斯顿工业大学在读博士生,个人的擅长领域为:利用Python进行空间数据(遥感G...

44970
来自专栏SAP最佳业务实践

SAP最佳业务实践:FI–现金管理(160)-14银企对账-客户收款-承兑汇票-F-36收到承兑汇票

4.5.2 F-36收到银行承兑汇票 收到客户银行承兑汇票支付应收账款,形成财务记账如下: 借:应收票据 贷:应收账款 ? 输入凭证日期、参照、抬头文本 回...

32180
来自专栏极乐技术社区

小程序音频API踩坑手册

80930
来自专栏FreeBuf

Bash漏洞再次演进:缓冲区溢出导致远程任意命令执行

近几天,“Shellshock”Bash漏洞的出现可谓是给安全界投放了一颗重型炸弹,越来越多的厂商和黑白帽子都纷纷加入到分析阵营当中,同时也接二连三爆出了更多针...

218100

扫码关注云+社区

领取腾讯云代金券