Асинхронная загрузка вложенных моделей в Django
У меня есть модели:
class ObjectA(models.Model):
alias = models.CharField(max_length=50)
objectb = models.ForeignKey(ObjectB, on_delete=models.PROTECT)
class Meta:
db_table = "objecta"
class ObjectB(models.Model):
name = models.CharField(max_length=50)
objectc = models.ForeignKey(ObjectC, on_delete=models.PROTECT)
class Meta:
db_table = "objectb"
class ObjectC(models.Model):
name = models.CharField(max_length=50)
class Meta:
db_table = "objectc"
В моей функции ViewSet
я хочу получить ObjectA
и затем получить имя из ссылки ObjectC
.
В синхронном Django я бы сделал
get_object_or_404(ObjectA, alias="My alias").objectb.objectc.name
Но при этом в async Django выдает ошибку:
django.core.exceptions.SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.
Я нашел решение, которое не кажется мне очень чистым:
from django.db.models.query import aprefetch_related_objects
from django.shortcuts import get_object_or_404
get_objecta_model = sync_to_async(get_object_or_404, thread_sensitive=True)
objecta = await get_objecta_model(ObjectA, name=alias)
await aprefetch_related_objects([objecta], "objectb__objectc")
objecta.objectb.objectc.name
Насколько мне известно, это одно из обходных решений, которое вы можете использовать в настоящее время. Отложенный поиск не поддерживается в режиме async.
Другой способ заключается в использовании явного .aget
с .select_related
вместо использования помощника get_object_or_404
:
try:
objecta = await ObjectA.objects.select_related("objectb__objectc").aget(name="foo")
objectc_name = objecta.objectb.objectc.name
except ObjectA.DoesNotFound:
return HttpResponseNotFound()