簡體   English   中英

芹菜 - 在tasks.py中導入模型

[英]Celery - importing models in tasks.py

我在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.

我嘗試過的事情

  1. 在tasks.py文件的頂部調用django.setup() - 原因

     raise RuntimeError("populate() isn't reentrant") 

    當放入send_email方法時也會導致相同的錯誤。 這些是對SO中其他類似問題的建議

  2. 在'send_email'方法中導入模型,允許worker啟動但導致以下錯誤

     raise AppRegistryNotReady("Apps aren't loaded yet.") 

    這是對SO中類似問題的另一個建議

  3. 在調用'send_email'函數時刪除.delay(使用在tasks.py文件或者send_email方法中的導入),但由於任務不再是異步,它沒有任何好處,但可能會縮小問題范圍?

注意事項?

  1. 我使用擴展AbstractBaseUser的自定義用戶模型,我在芹菜中看到了許多與此有關的github問題,但這些問題是在celery v3.1中修復的,所以我相信
  2. 我在芹菜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個環境? 這可能是問題嗎?

  3. 這可能與否有關,但為了讓我的自定義用戶模型在我的app / models.py中工作,我只有一行導入用戶模型,否則我得到一個

     django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'myApi.User' that has not been installed 
  4. 我試圖將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()

任何建議將不勝感激。 也很遺憾長篇文章,這是我的第一個,所以不知道需要多少細節。

我發現了我的問題。 如果它幫助其他任何人堅持這個我需要添加線

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

為芹菜

希望這有助於其他人,因為我花了太多時間來解決這個問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM