我在tasks.py
中访问模型时遇到问题我的目标是在应用程序的各个部分发送电子邮件(用户注册,重置密码等)。为此,我将用户ID传递给名为' send_email'的芹菜任务。
@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'中导入模型方法,允许工作人员启动但导致以下错误
raise AppRegistryNotReady("Apps aren't loaded yet.")
这是对SO
在调用' send_email'时删除.delay有效的函数(在tasks.py文件或send_email方法的顶部导入),但由于任务不再是异步,它没有任何好处,但可能会缩小问题范围?
注意事项?
我在celery v4.1,django 1.11.10,python 2.7上使用RabbitMQ作为Broker并在虚拟环境中运行worker / server。我正在使用
启动我的工作人员celery -A api worker -l info
在终端窗口上然后使用pycharm的终端使用
启动服务器python manage.py runserver
如此有效地有2个环境?这可能是问题吗?
这可能与否有关,但是为了让我的自定义用户模型在我的app / models.py中工作,我只有一行导入User模型,否则我得到了
django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'myApi.User' that has not been installed
我尝试将auth模型设置为' 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()
任何建议都将不胜感激。对于长篇文章也很抱歉,这是我的第一个,所以不确定需要多少细节。
答案 0 :(得分:2)
我发现了我的问题。如果它帮助其他人坚持这个我需要添加行
sys.path.append(os.path.abspath('api'))
在我的celerySettings.py中,用于拾取模型。
现在看起来像这样
from __future__ import absolute_import, unicode_literals
from django.conf import settings
import os, sys
from celery import Celery
sys.path.append(os.path.abspath('api'))
# 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))
然后我在实际尝试在本地查询数据库的模型时遇到了另一个问题。 Celery说我的数据库表不存在,这是因为它创建了一个新的数据库,上面是一个实际的本地数据库文件所在的文件夹,修复它我只需要更改数据库名称
"db.sqlite3"
到
os.path.join(os.path.dirname(__file__), "db.sqlite3")
在settings.py 中
有效地将其更改为
api/db.sqlite3
for Celery
希望这有助于其他人,因为我花了太多时间来解决这个问题。