Django+Celery+RabbitMQ

  1. 需要在项目目录下创建一个新的celery.py文件(与setting.py同级)

    # celery.py
    from celery import Celery
    
    # Set the default Django settings module for the 'celery' program.
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')
    
    app = Celery('proj')
    
    # Using a string here means the worker doesn't have to serialize
    # the configuration object to child processes.
    # - namespace='CELERY' 所有和Celery相关的配置需要前缀为CELERY_,防止与Django的配置重叠
    app.config_from_object('django.conf:settings', namespace='CELERY')
    
    # 将来自Django应用的任务自动注册到Celery中
    app.autodiscover_tasks()
    """
    应用中有tasks.py就能自动发现
    - app1/
        - tasks.py
        - models.py
    - app2/
        - tasks.py
        - models.py
    """
    
    
    @app.task(bind=True)
    def debug_task(self):
        print(f'Request: {self.request!r}')
    
    # settings.py
    # Celery Configuration Options
    CELERY_TIMEZONE = "Australia/Tasmania"
    CELERY_TASK_TRACK_STARTED = True
    CELERY_TASK_TIME_LIMIT = 30 * 60
    
  2. 需要在项目目录下个的_init.py_.py中导入这个应用程序,一遍@shared_task装饰器使用

    from .celery import app as celery_app
    
    __all__ = ('celery_app',) 
    
  3. 在各应用中的tasks.py中使用的装饰器是@shared_task,而不是@app.task

  4. django-celery-results,使用Django ORM/Cache作为结果后端

    1. pip install django-celery-results

    2. # settings.py
      INSTALLED_APPS = (
          ...,
          'django_celery_results',	# 注意此处是下划线
      )
      
      # CELERY_RESULT_BACKEND = 'django-db'
      CELERY_CACHE_BACKEND = 'default'
      CACHES = {
          'default': {
              'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
              'LOCATION': 'my_cache_table',
          }
      }
      
    3. 通过执行数据库迁移来创建 Celery 数据库表

      python manage.py migrate django_celery_results
      
  5. django-celery-beats,管理定期任务

    1. pip install django-celery-beats
    # setting.py
    INSTALLED_APPS = (
        ...,
        'django_celery_beat',
    )
    
    python manage.py migrate
    celery -A proj beat -l INFO --scheduler django_celery_beat.schedulers:DatabaseScheduler
    
  6. 启动工作进程

    python manage.py celery -A proj worker -l INFO
    
  7. 示例

    # blog/models.py
    from django.db import models
    from django.utils.translation import ugettext_lazy as _
    
    
    class Comment(models.Model):
        name = models.CharField(_('name'), max_length=64)
        email_address = models.EmailField(_('email address'))
        homepage = models.URLField(_('home page'),
                                   blank=True, verify_exists=False)
        comment = models.TextField(_('comment'))
        pub_date = models.DateTimeField(_('Published date'),
                                        editable=False, auto_add_now=True)
        is_spam = models.BooleanField(_('spam?'),
                                      default=False, editable=False)
    
        class Meta:
            verbose_name = _('comment')
            verbose_name_plural = _('comments')
    
    # blog/views.py
    from django.http import HttpResponseRedirect
    from django.template.context import RequestContext
    from django.shortcuts import get_object_or_404, render_to_response
    
    from blog import tasks
    from blog.models import Comment
    
    
    class CommentForm(forms.ModelForm):
    
        class Meta:
            model = Comment
    
    
    def add_comment(request, slug, template_name='comments/create.html'):
        post = get_object_or_404(Entry, slug=slug)
        remote_addr = request.META.get('REMOTE_ADDR')
    
        if request.method == 'post':
            form = CommentForm(request.POST, request.FILES)
            if form.is_valid():
                comment = form.save()
                # 异步检查垃圾邮件
                tasks.spam_filter.delay(comment_id=comment.id,
                                        remote_addr=remote_addr)
                return HttpResponseRedirect(post.get_absolute_url())
        else:
            form = CommentForm()
    
        context = RequestContext(request, {'form': form})
        return render_to_response(template_name, context_instance=context)
    
    # blog/tasks.py
    from celery import Celery,shared_task
    
    from akismet import Akismet
    
    from django.core.exceptions import ImproperlyConfigured
    from django.contrib.sites.models import Site
    
    from blog.models import Comment
    
    
    app = Celery(broker='amqp://')
    
    
    @shared_task
    def spam_filter(comment_id, remote_addr=None):
        logger = spam_filter.get_logger()
        logger.info('Running spam filter for comment %s', comment_id)
    
        comment = Comment.objects.get(pk=comment_id)
        current_domain = Site.objects.get_current().domain
        akismet = Akismet(settings.AKISMET_KEY, 'http://{0}'.format(domain))
        if not akismet.verify_key():
            raise ImproperlyConfigured('Invalid AKISMET_KEY')
    
    
        is_spam = akismet.comment_check(user_ip=remote_addr,
                            comment_content=comment.comment,
                            comment_author=comment.name,
                            comment_author_email=comment.email_address)
        if is_spam:
            comment.is_spam = True
            comment.save()
    
        return is_spam
    
posted @ 2021-09-02 20:33  注入灵魂  阅读(142)  评论(0)    收藏  举报