作为 celery 任务参数的 Django 模型对象引发 EncodeError - 'object of type someModelName is not JSON serializable'
Django model object as parameter for celery task raises EncodeError - 'object of type someModelName is not JSON serializable'
我正在处理一个 django 项目(我对 django 很陌生),运行 遇到了在我的视图和 celery 任务之间传递模型对象的问题。
我正在从包含多个 ModelChoiceField 字段的表单中获取输入,并在 celery 任务中使用所选对象。当我使用 someTask.delay(x, y, z) 对任务(来自视图中的 post 方法)进行排队时,其中 x、y 和 z 是来自 ModelChoiceFields 表单的各种对象,我得到错误 object of type <someModelName> is not JSON serializable
.
就是说,如果我创建一个简单的测试函数并将任何相同的对象从表单传递到该函数,我将得到预期的行为,并且在表单中选择的对象的名称被记录下来。
def test(object):
logger.debug(object.name)
我根据上述错误进行了一些探索,发现 django serializers 允许通过在将对象传递给 celery 任务之前在视图中使用 serializers.serialize('json', [template]),
序列化对象来解决此问题。
然后我可以通过使用 template = json.loads(template)[0].get('fields')
访问 celery 任务中的对象来访问它所需的位作为字典——虽然这有效,但它看起来有点不雅,我想看看是否有我在这里缺少的东西。
我显然对这里的任何 feedback/guidance 持开放态度,但我的主要问题是:
为什么我在将模型对象传递到 celery 任务时出现 object...is not JSON serializable
错误,但在传递到我的简单测试函数时却没有?
在对 celery 任务进行排队之前使用 django 序列化程序的方法被认为是 acceptable/correct 还是有更简洁的方法来实现这个目标?
如有任何建议,我们将不胜感激。
回溯:
我也尝试 post 完整的追溯,但是包括导致 post 被标记为 'this looks like spam'
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)
将此行添加到 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 模型实例在 celery 环境中不可用,因为它在不同的进程中运行
那么如何在任务中获取模型实例呢?好吧,您可以执行以下操作 -
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
我正在处理一个 django 项目(我对 django 很陌生),运行 遇到了在我的视图和 celery 任务之间传递模型对象的问题。
我正在从包含多个 ModelChoiceField 字段的表单中获取输入,并在 celery 任务中使用所选对象。当我使用 someTask.delay(x, y, z) 对任务(来自视图中的 post 方法)进行排队时,其中 x、y 和 z 是来自 ModelChoiceFields 表单的各种对象,我得到错误 object of type <someModelName> is not JSON serializable
.
就是说,如果我创建一个简单的测试函数并将任何相同的对象从表单传递到该函数,我将得到预期的行为,并且在表单中选择的对象的名称被记录下来。
def test(object):
logger.debug(object.name)
我根据上述错误进行了一些探索,发现 django serializers 允许通过在将对象传递给 celery 任务之前在视图中使用 serializers.serialize('json', [template]),
序列化对象来解决此问题。
然后我可以通过使用 template = json.loads(template)[0].get('fields')
访问 celery 任务中的对象来访问它所需的位作为字典——虽然这有效,但它看起来有点不雅,我想看看是否有我在这里缺少的东西。
我显然对这里的任何 feedback/guidance 持开放态度,但我的主要问题是:
为什么我在将模型对象传递到 celery 任务时出现
object...is not JSON serializable
错误,但在传递到我的简单测试函数时却没有?在对 celery 任务进行排队之前使用 django 序列化程序的方法被认为是 acceptable/correct 还是有更简洁的方法来实现这个目标?
如有任何建议,我们将不胜感激。
回溯: 我也尝试 post 完整的追溯,但是包括导致 post 被标记为 'this looks like spam'
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)
将此行添加到 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 模型实例在 celery 环境中不可用,因为它在不同的进程中运行
那么如何在任务中获取模型实例呢?好吧,您可以执行以下操作 -
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