【发布时间】:2018-05-07 10:30:55
【问题描述】:
我在访问我的 tasks.py 中的模型时遇到问题
我的目标是在应用程序的各个部分(用户注册、重置密码等)发送电子邮件。为此,我将用户 ID 传递给名为“send_email”的 celery 任务。
@shared_task()
def send_email(sender_id=None, receiver_id=None, type=None, message=None):
sender = User.objects.get(id=sender_id)
receiver = User.objects.get(id=receiver_id)
logger.info("Starting send email")
Email.send_email(sender, receiver, type, message)
logger.info("Finished send email")
然后任务需要使用 id 来检索用户并向他们发送电子邮件。尝试将 User 模型导入 tasks.py 文件时会出现这种情况。
我收到一个错误
raise AppRegistryNotReady("Apps aren't loaded yet.") django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
我尝试过的事情
-
在 tasks.py 文件顶部调用 django.setup() - 原因
raise RuntimeError("populate() isn't reentrant")放入 send_email 方法时也会导致相同的错误。这些是对 SO 中其他类似问题的建议
-
在'send_email'方法中导入模型,允许worker启动但导致以下错误
raise AppRegistryNotReady("Apps aren't loaded yet.")这是关于 SO 中类似问题的另一个建议
在调用 'send_email' 函数时删除 .delay 有效(在 tasks.py 文件顶部或在 send_email 方法中导入)但由于任务不再是异步的,它没有任何好处,但可能会缩小解决问题?
注意事项?
- 我使用扩展 AbstractBaseUser 的自定义用户模型,我在 celery 中看到了许多与此相关的 github 问题,但我相信这些问题应该在 celery v3.1 中得到修复
-
我正在使用 celery v4.1、django 1.11.10、python 2.7,并且正在使用 RabbitMQ 作为代理并在虚拟环境上运行工作程序/服务器。我正在使用
celery -A api worker -l info在终端窗口上,然后使用 pycharm 的终端使用
启动服务器python manage.py runserver那么有效地有 2 个环境?会不会是这个问题?
-
这可能相关或不相关,但为了让我的自定义用户模型在我的 app/models.py 中工作,我只有一行导入用户模型,否则我会得到一个
django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'myApi.User' that has not been installed -
我尝试将身份验证模型设置为“myApi.user.User”(用户是声明模型的文件夹,但得到一个
Invalid model reference 'myApi.user.User'. String model references must be of the form 'app_label.ModelName'.所以我猜这就是为什么需要在 myApi/models.py 中导入以便可以在此处获取它?
项目结构
├── api
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── celerySettings.py # my celery.py
├── db.sqlite3
├── myApi
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── tasks.py
│ ├── urls.py
│ ├── user
│ │ ├── __init__.py
│ │ ├── managers.py
│ │ ├── models.py
│ │ ├── serializers.py
│ │ ├── urls.py
│ │ └── views.py
│ ├── utils
│ │ └── Email.py
│ ├── views.py
├── manage.py
└── static
tasks.py
from __future__ import absolute_import, unicode_literals
from celery.schedules import crontab
from celery.task import periodic_task
from celery.utils.log import get_task_logger
from celery import shared_task
from celery import current_app
from .user.models import User
from .utils import Email
logger = get_task_logger(__name__)
@shared_task()
def send_email(sender_id=None, receiver_id=None, type=None, message=None):
sender = User.objects.get(id=sender_id)
receiver = User.objects.get(id=receiver_id)
logger.info("Starting send email")
Email.send_email(sender, receiver, type, message)
logger.info("Finished send email")
settings.py
....
INSTALLED_APPS = [
'rest_framework',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'corsheaders',
'myApi',
'celery',
'rest_framework.authtoken',
'rest_framework.renderers',
]
AUTH_USER_MODEL = 'myApi.User'
CELERY_IMPORTS = ('api.myApi.tasks')
....
celerySettings.py
from __future__ import absolute_import, unicode_literals
from django.conf import settings
import os
from celery import Celery
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'api.api.settings')
app = Celery('api', broker='amqp://')
# Using a string here means the worker doesn't have to serialize
# the configuration object to child processes.
# - namespace='CELERY' means all celery-related configuration keys
# should have a `CELERY_` prefix.
app.config_from_object(settings, namespace='CELERY')
# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
myApi/models.py
from user.models import User
myApi/admin.py
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib import admin
from user.models import User
admin.site.register(User)
api/wsgi.py
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings")
application = get_wsgi_application()
任何建议将不胜感激。也很抱歉这么长的帖子,这是我的第一篇,所以不确定需要多少细节。
【问题讨论】:
-
你试过在 celerySettings.py 顶部附近调用
django.setup()吗? -
@Leighton 是的,抱歉我忘了提这个。当我将它添加到 tasks.py 时,我得到了相同的可重入错误
-
你改变了你的 wsgi.py 吗?可重入错误通常意味着您的 settings.py 不正确,或者与加载 apache/WSGI 相关的配置错误。我假设该站点可以正常运行(并且它只是无法正常工作的芹菜)?
-
@Leighton 我不相信我这样做了,我已经编辑了问题以包含它。该 api 运行良好,它只为有问题的 celery 任务导入模型。也感谢您的帮助