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 %}
  

{{ topic.title }}

{% endfor %}

{# 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 %} "?page={{ page_number }}">{{ page_number }} {% endifequal %} {% endfor %}

{% if topics.has_previous %} "?page={{ topics.previous_page_number }}">Previous {% endif %} {# topics.paginator.number_pages 返回总页数 #} Page {{ topics.number }} of {{ topics.paginator.num_pages }}. {% if topics.has_next %} "?page={{ topics.next_page_number }}">Next {% endif %}

但是在这里的解决方案不太适用,当前的结果并不是存在数据库里面的,而是实时查询爬取解析得来的,那么,这种分页方案似乎是不太适用,没办法,最后采取的方式是爬取特定或全部的页面,存入数据库,然后进一步的分页展示.这里就到了第一个问题:能否后台运行爬取任务,翻页时减少等待.
这里就需要用到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. 文中链接引用

你可能感兴趣的:(Python)