Iqb*_*wan 1 python django django-orm python-asyncio discord.py
我正在尝试为 Django 网站制作一个不和谐的机器人。在实现的时候我发现Django数据库不允许异步操作,我们必须使用线程或sync_to_async.
我使用过sync_to_async并且似乎有效。但后来我遇到了一个问题,我什至无法弄清楚它出了什么问题以及那里发生了什么。
谁能解释我在那里做错了什么以及那里发生了什么?
@sync_to_async
def get_customer(id):
try:
return Customer.objects.get(discord_id=id)
except:
return None
#------
@bot.command()
async def categories(ctx):
customer = await get_customer(ctx.author.id) #this line of code works well
categories = await sync_to_async(Category.objects.all().filter)(customer=customer)
#categories = await sync_to_async(Category.objects.filter)(customer=customer)#I tried this also, didn't work
print(categories) #problem is in the line
embed = Embed(title='', description="{}".format('\n'.join([ x.name for x in categories])))
await ctx.send(embed=embed)
Run Code Online (Sandbox Code Playgroud)
我收到的回溯错误是:
Running bot
Ignoring exception in command categories:
Traceback (most recent call last):
File "/Users/rhidwan/Desktop/personal_transaction/venv/lib/python3.7/site-packages/discord/ext/commands/core.py", line 83, in wrapped
ret = await coro(*args, **kwargs)
File "discord_bot.py", line 76, in categories
print(categories)
File "/Users/rhidwan/Desktop/personal_transaction/venv/lib/python3.7/site-packages/django/db/models/query.py", line 252, in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "/Users/rhidwan/Desktop/personal_transaction/venv/lib/python3.7/site-packages/django/db/models/query.py", line 276, in __iter__
self._fetch_all()
File "/Users/rhidwan/Desktop/personal_transaction/venv/lib/python3.7/site-packages/django/db/models/query.py", line 1261, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/Users/rhidwan/Desktop/personal_transaction/venv/lib/python3.7/site-packages/django/db/models/query.py", line 57, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/Users/rhidwan/Desktop/personal_transaction/venv/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 1150, in execute_sql
cursor = self.connection.cursor()
File "/Users/rhidwan/Desktop/personal_transaction/venv/lib/python3.7/site-packages/django/utils/asyncio.py", line 24, in inner
raise SynchronousOnlyOperation(message)
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/rhidwan/Desktop/personal_transaction/venv/lib/python3.7/site-packages/discord/ext/commands/bot.py", line 892, in invoke
await ctx.command.invoke(ctx)
File "/Users/rhidwan/Desktop/personal_transaction/venv/lib/python3.7/site-packages/discord/ext/commands/core.py", line 797, in invoke
await injected(*ctx.args, **ctx.kwargs)
File "/Users/rhidwan/Desktop/personal_transaction/venv/lib/python3.7/site-packages/discord/ext/commands/core.py", line 92, in wrapped
raise CommandInvokeError(exc) from exc
discord.ext.commands.errors.CommandInvokeError: Command raised an exception: SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
Run Code Online (Sandbox Code Playgroud)
如果您仍然需要帮助解决该问题;
似乎这个问题与 Django 中查询集的惰性求值有关。基本上,当你打电话时
MyModel.objects.filter(key=value)
Run Code Online (Sandbox Code Playgroud)
查询集不会立即评估,它仅在您使用它时评估,这可能是迭代它,将其转换为列表,或获取它的字符串表示形式。
在您的示例中,即使您使用sync_to_async包装您的Django调用,当您想要使用以下方式打印查询集时,也会评估查询集:
print(categories)
Run Code Online (Sandbox Code Playgroud)
由于它处于异步上下文中,因此您会收到错误。为了避免这种情况,您可以强制在sync_to_async内评估查询集,例如
@sync_to_async
def get_categories_value(customer):
return list(Category.objects.all().filter(customer=customer))
...
categories = await get_categories_value()
print(categories)
Run Code Online (Sandbox Code Playgroud)