django分页和消息队列

来源:互联网 发布:2017淘宝怎么删除差评 编辑:程序博客网 时间:2024/06/17 14:24


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

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

Paginator

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

from django.core.paginator import Paginatorfrom django.core.paginator import EmptyPagefrom django.core.paginator import PageNotAnIntegerfrom hello.models import Topicdef 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_literalsfrom django-celery-results import modelsfrom celery import shared_task@shared_taskdef 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. 文中链接引用
1 0