Я работаю с проектом django (я новичок в django) и сталкиваюсь с проблемой передачи объекта модели между моим представлением и задачей сельдерея.

Я беру данные из формы, которая содержит несколько ModelChoiceField полей и используя выбранный объект в задаче сельдерея. Когда я ставлю задачу в очередь (из метода post в представлении), используя someTask.delay (x, y, z), где x, y и z - различные объекты из формы ModelChoiceFields, я получаю сообщение об ошибке object of type <someModelName> is not JSON serializable.

Тем не менее, если я создаю простую тестовую функцию и передаю любой из тех же объектов из формы в функцию, я получаю ожидаемое поведение, и имя объекта, выбранного в форме, регистрируется.

def test(object):
    logger.debug(object.name)

Я сделал несколько попыток на основе указанной выше ошибки и нашел сериализаторы django, которые позволяет обходной путь путем сериализации объекта с помощью serializers.serialize('json', [template]), в представлении перед передачей его в задачу сельдерея.

Затем я могу получить доступ к объекту в задаче сельдерея, используя template = json.loads(template)[0].get('fields') для доступа к его необходимым битам в качестве словаря - хотя это работает, оно кажется немного неэлегантным, и я хотел увидеть, есть ли что-то, чего мне здесь не хватает .

Я, очевидно, открыт для любых отзывов / рекомендаций здесь, однако мои основные вопросы:

  • Почему я получаю ошибку object...is not JSON serializable при передаче объекта модели в задачу сельдерея, но не при переходе к моей простой тестовой функции?

  • Считается ли подход с использованием сериализаторов django перед постановкой задачи сельдерея в очередь приемлемым / правильным или есть более чистый способ достижения этой цели?

Любые предложения будут ценны.

Отслеживание: я попытался опубликовать здесь полную обратную связь, однако в том числе это привело к тому, что сообщение было помечено как «это похоже на спам».

Internal Server Error: /build/
Traceback (most recent call last):
  File "/home/tech/sandbox_project/venv/lib/python3.8/site-packages/kombu/serialization.py", line 49, in _reraise_errors
    yield
  File "/home/tech/sandbox_project/venv/lib/python3.8/site-packages/kombu/serialization.py", line 220, in dumps
    payload = encoder(data)
  File "/home/tech/sandbox_project/venv/lib/python3.8/site-packages/kombu/utils/json.py", line 65, in dumps
    return _dumps(s, cls=cls or _default_encoder,
  File "/usr/lib/python3.8/json/__init__.py", line 234, in dumps
    return cls(
  File "/usr/lib/python3.8/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/lib/python3.8/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/home/tech/sandbox_project/venv/lib/python3.8/site-packages/kombu/utils/json.py", line 55, in default
    return super().default(o)
  File "/usr/lib/python3.8/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type Template is not JSON serializable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/tech/sandbox_project/venv/lib/python3.8/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
1
automate 11 Фев 2021 в 21:20

1 ответ

Лучший ответ

Добавьте эти строки в settings.py

# Project/settings.py
CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'
CELERY_RESULT_SERIALIZER = 'json'

Затем вместо передачи объекта отправьте JSON с id/pk, если вы используете экземпляр модели, вызовите задачу следующим образом ..

test.delay({'pk': 1})

Экземпляр модели Django недоступен в среде сельдерея, так как он выполняется в другом процессе

Как же тогда получить экземпляр модели внутри задачи? Что ж, вы можете сделать что-то вроде ниже -

def import_django_instance():
    """
    Makes django environment available 
    to tasks!!
    """
    import django
    import os
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'Project.settings')
    django.setup()


# task
@shared_task(name="simple_task")
def simple_task(data):
    import_django_instance()
    from app.models import AppModel

    pk = data.get('pk')
    instance = AppModel.objects.get(pk=pk)
    # your operation
0
Raihan Kabir 13 Фев 2021 в 10:48