django分页和消息队列


起源于一个神奇的项目,内容就是爬取搜索引擎的搜索重新建立一个搜索入口.然后就碰到了一些问题:
1. 一次性爬取所有页面的话爬取速度是一个问题,能不能爬一页的内容先展示出来,后台继续爬取第二页及以后的页面,在继续展示?
2. 爬取的结果展示出来是需要进行分页的,如何分页?

这里首先讲解一下如何分页

Paginator

在django中分页采用的是Paginator,举个例子

from django.core.paginator import Paginator
from django.core.paginator import EmptyPage
from django.core.paginator import PageNotAnInteger
from hello.models import Topic


def index(request):
    limit = 3  # 每页显示的记录数
    topics = Topic.objects.all()
    paginator = Paginator(topics, limit)  # 实例化一个分页对象

    page = request.GET.get('page')  # 获取页码
    try:
        topics = paginator.page(page)  # 获取某页对应的记录
    except PageNotAnInteger:  # 如果页码不是个整数
        topics = paginator.page(1)  # 取第一页的记录
    except EmptyPage:  # 如果页码太大,没有相应的记录
        topics = paginator.page(paginator.num_pages)  # 取最后一页的记录

    return render_to_response('index.html', {'topics': topics})

然后在模板里面的稍作修改即可

{% for topic in topics.object_list %}
  <p>{{ topic.title }}</p>
{% endfor %}

<!-- 第一种分页显示方式 -->
<p>
  {# topics.paginator.page_range 这个函数返回包含一个所有页码数的 range 对象 #}
  {# 即 range(1, topics.paginator.num_pages + 1) #}
  {% for page_number in topics.paginator.page_range %}
    {% ifequal page_number  topics.number %}
      {{ page_number }}
    {% else %}
      <a href="?page={{ page_number }}">{{ page_number }}</a>
    {% endifequal %}
  {% endfor %}
</p>


<!-- 另一种分页显示方式 -->
<p>
{% if topics.has_previous %}
  <a href="?page={{ topics.previous_page_number }}">Previous</a>
  {% endif %}
  {# topics.paginator.number_pages 返回总页数 #}
  Page {{ topics.number }} of {{ topics.paginator.num_pages }}.
{% if topics.has_next %}
  <a href="?page={{ topics.next_page_number }}">Next</a>
{% endif %}
</p>

但是在这里的解决方案不太适用,当前的结果并不是存在数据库里面的,而是实时查询爬取解析得来的,那么,这种分页方案似乎是不太适用,没办法,最后采取的方式是爬取特定或全部的页面,存入数据库,然后进一步的分页展示.这里就到了第一个问题:能否后台运行爬取任务,翻页时减少等待.
这里就需要用到celery,注意的一点是以前的版本需要一个单独的django-celery保障django和celery的联合使用,现在不需要了,一个celery库即可.

Celery

按照官方教程配置,建议不懂celery的,先看一下这个,如果出现server问题,解决方案一般是需要安装对应的server,如redis等. 另外重要的一点为了能够使用后台运行的结果,按照教程中需要安装django-celery-results,同时在后台task函数里面,将结果保存在django_celery_results.models.TaskResult里面,

from __future__ import absolute_import, unicode_literals
from django-celery-results import models
from celery import shared_task
@shared_task
def func(x, y):
    result = somefunction(x+y)
    id = anotherfunction(x+y)
    django_result = models.TaskResult(task_id = id,result=result)
    django_result.save()
    return id

在后台运行的结果就可以task_id重新查询到,当然在这里如果考虑到实时和数据库容量的问题,则需要定时或者在sseion结束时删除掉对应task_id的运行结果,这里同样需要用celery制定一个定时任务
Tips:
1. 在运行celery -A proj worker –loglevel=info出现问题”server channel error 406, message: PRECONDITION_FAILED”的一个原因可能是你在另外一个地方运行了同样的celery 任务,这里需要的就是关掉其他运行的celery任务,就没有问题了.
2. 查看文档比查看博客来的准确,查github作为具体项目的借鉴.

参考文献

  1. https://mozillazg.github.io/2013/01/django-pagination-by-use-paginator.html
  2. 文中链接引用
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值