Сельдерей - импорт моделей в tasks.py - PullRequest
0 голосов
/ 07 мая 2018

У меня проблема с получением доступа к моделям в tasks.py

Моя цель - отправить электронное письмо в различные части приложения (регистрация пользователя, сброс пароля и т. Д.). Для этого я передаю идентификаторы пользователя задаче сельдерея с именем 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")

Затем задача должна использовать идентификатор, чтобы получить пользователя и отправить ему электронное письмо. Это ломается при попытке импортировать модель User в файл tasks.py.

Я получаю сообщение об ошибке

raise AppRegistryNotReady("Apps aren't loaded yet.") django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

Вещи, которые я пробовал

  1. вызов django.setup () в верхней части файла tasks.py - вызывает

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

    вызывает ту же ошибку, когда помещается в метод send_email. Это были предложения по другим подобным вопросам в SO

  2. Импорт модели в метод 'send_email', позволяет запускать рабочий, но вызывает следующую ошибку

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

    Это было еще одно предложение по аналогичному вопросу в SO

  3. Удаление .delay при вызове функции 'send_email', которая работает (с импортом в верхней части файла tasks.py или в методе send_email), но поскольку задача больше не асинхронная, она не приносит никакой пользы, но, возможно, сужается вниз вопрос?

Примечания?

  1. Я использую пользовательскую модель, которая расширяет AbstractBaseUser, я видел ряд проблем с github в сельдерее, связанных с этим, но они должны были быть исправлены в сельдерее v3.1 или около того, я полагаю
  2. Я нахожусь на сельдерее v4.1, django 1.11.10, python 2.7 и использую RabbitMQ в качестве брокера и работаю в режиме рабочий / сервер в виртуальной среде. Я начинаю свой рабочий, используя

    celery -A api worker -l info
    

    в окне терминала, а затем с помощью терминала pycharm запустить сервер, используя

    python manage.py runserver
    

    так эффективно есть 2 envs? Может ли это быть проблемой?

  3. Это может или не быть связано, но для того, чтобы моя пользовательская модель работала в моем app / models.py, у меня есть только одна строка, которая импортирует пользовательскую модель, в противном случае я получаю

    django.core.exceptions.ImproperlyConfigured: AUTH_USER_MODEL refers to model 'myApi.User' that has not been installed
    
  4. Я попытался установить для модели аутентификации 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)

апи / wsgi.py

import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "api.settings")

application = get_wsgi_application()

Любые предложения будут с благодарностью. Также извините за длинный пост, он мой первый, поэтому я не был уверен, сколько деталей понадобилось.

1 Ответ

0 голосов
/ 13 мая 2018

Я нашел свою проблему.В случае, если это поможет кому-то, кто застрял на этом, мне нужно было добавить строку

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))

Затем я столкнулся с другой проблемой, когда пытался запросить базу данных для моих моделей локально.Селери говорил, что моих таблиц базы данных не существует, потому что он создавал новую базу данных на одну папку выше, где находился фактический файл локальной базы данных, чтобы исправить это, мне просто нужно было изменить имя базы данных

"db.sqlite3"

на

os.path.join(os.path.dirname(__file__), "db.sqlite3")

в settings.py

, который фактически меняет его на

api/db.sqlite3

для сельдерея

Надеюсь, это поможет кому-то другому, пока я потратилслишком много времени для борьбы с этим вопросом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...