到目前为止,这是我们所做的问题。 您可能已经注意到创建用户有点慢。 这是因为Django在请求时间内发送了验证电子邮件。
它是这样工作的:我们将用户数据发送到Django应用程序。 该应用程序创建User
模型,然后创建与Gmail(或您选择的其他服务)的连接。 Django等待响应,然后才将响应返回到我们的浏览器。
这是芹菜的来源。首先,确保已安装它:
$ pip install Celery
现在,我们需要在Django应用程序中创建一个Celery应用程序:
# quick_publisher/celery.py
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'quick_publisher.settings')
app = Celery('quick_publisher')
app.config_from_object('django.conf:settings')
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
芹菜是一个任务队列。 它从我们的Django应用程序接收任务,并将在后台运行它们。 芹菜需要与其他充当经纪人的服务配对。
中介在Web应用程序和Celery之间发送消息。 在本教程中,我们将使用Redis。 Redis易于安装,我们可以轻松入门,而不必大惊小怪。
您可以按照“ Redis快速入门”页面上的说明安装Redis。 您需要安装Redis Python库, pip install redis
以及使用Redis和Celery所需的捆绑软件: pip install celery[redis]
。
在一个单独的控制台中启动Redis服务器,如下所示: $ redis-server
让我们将与Celery / Redis相关的配置添加到quick_publisher/settings.py
:
# REDIS related settings
REDIS_HOST = 'localhost'
REDIS_PORT = '6379'
BROKER_URL = 'redis://' + REDIS_HOST + ':' + REDIS_PORT + '/0'
BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 3600}
CELERY_RESULT_BACKEND = 'redis://' + REDIS_HOST + ':' + REDIS_PORT + '/0'
在Celery中运行任何东西之前,必须将其声明为任务。
这样做的方法如下:
# main/tasks.py
import logging
from django.urls import reverse
from django.core.mail import send_mail
from django.contrib.auth import get_user_model
from quick_publisher.celery import app
@app.task
def send_verification_email(user_id):
UserModel = get_user_model()
user = UserModel.objects.get(pk=user_id)
send_mail(
'Verify your QuickPublisher account',
'Follow this link to verify your account: '
'http://localhost:8000%s' % reverse('verify', kwargs={'uuid': str(user.verification_uuid)}),
'from@quickpublisher.dev',
[user.email],
fail_silently=False,
except UserModel.DoesNotExist:
logging.warning("Tried to send verification email to non-existing user '%s'" % user_id)
我们在这里所做的是:我们将发送验证电子邮件功能移到另一个名为tasks.py
文件中。
一些注意事项:
- 文件名很重要。 Celery浏览
INSTALLED_APPS
所有应用程序,并将任务注册在tasks.py
文件中。 - 注意我们如何用
@app.task
装饰send_verification_email
函数。 这告诉Celery这是将在任务队列中运行的任务。 - 注意,我们如何期望作为参数
user_id
而不是User
对象。 这是因为在将任务发送给Celery时,我们可能无法序列化复杂对象。 最好使其保持简单。
回到main/models.py
,信号代码变成:
from django.db.models import signals
from main.tasks import send_verification_email
def user_post_save(sender, instance, signal, *args, **kwargs):
if not instance.is_verified:
# Send verification email
send_verification_email.delay(instance.pk)
signals.post_save.connect(user_post_save, sender=User)
注意我们如何在任务对象上调用.delay
方法。 这意味着我们会将任务发送给Celery,而我们不必等待结果。 如果改为使用send_verification_email(instance.pk)
,我们仍将其发送给Celery,但将等待任务完成,这不是我们想要的。
在开始创建新用户之前,有一个陷阱。 芹菜是一项服务,我们需要启动它。 打开一个新控制台,确保您激活了适当的virtualenv,然后导航到项目文件夹。
$ celery worker -A quick_publisher --loglevel=debug --concurrency=4
这将启动四位芹菜加工工人。 是的,现在您终于可以创建另一个用户了。 请注意没有延迟,并确保在Celery控制台中查看日志,并查看任务是否正确执行。 看起来应该像这样:
[2017-04-28 15:00:09,190: DEBUG/MainProcess] Task accepted: main.tasks.send_verification_email[f1f41e1f-ca39-43d2-a37d-9de085dc99de] pid:62065
[2017-04-28 15:00:11,740: INFO/PoolWorker-2] Task main.tasks.send_verification_email[f1f41e1f-ca39-43d2-a37d-9de085dc99de] succeeded in 2.5500912349671125s: None
这是另一种常见情况。 大多数成熟的Web应用程序都会向其用户发送生命周期电子邮件,以保持其参与度。 生命周期电子邮件的一些常见示例:
- 每月报告
- 活动通知(喜欢,友情请求等)
- 提醒您完成某些操作(“不要忘记激活您的帐户”)
这是我们将在应用程序中执行的操作。 我们将计算每个帖子被查看了多少次,并将每日报告发送给作者。 每天一次,我们将遍历所有用户,获取他们的帖子,并发送包含表格的电子邮件,该表格包含帖子和查看次数。
让我们更改Post
模型,以便我们可以容纳视图计数方案。
class Post(models.Model):
author = models.ForeignKey(User)
created = models.DateTimeField('Created Date', default=timezone.now)
title = models.CharField('Title', max_length=200)
content = models.TextField('Content')
slug = models.SlugField('Slug')
view_count = models.IntegerField("View Count", default=0)
def __str__(self):
return '"%s" by %s' % (self.title, self.author)
与往常一样,当我们更改模型时,我们需要迁移数据库:
$ ./manage.py makemigrations
$ ./manage.py migrate
让我们还修改view_post
Django视图以计算视图:
def view_post(request, slug):
post = Post.objects.get(slug=slug)
except Post.DoesNotExist:
raise Http404("Poll does not exist")
post.view_count += 1
post.save()
return render(request, 'post.html', context={'post': post})
在模板中显示view_count
很有用。 将此<p>Viewed {{ post.view_count }} times</p>
到publisher/templates/post.html
文件中的某个publisher/templates/post.html
。 现在对帖子进行一些查看,看看计数器如何增加。
让我们创建一个芹菜任务。 由于它是关于帖子的,因此我将其放置在publisher/tasks.py
: