#load many to many relations
23 messages · Page 1 of 1 (latest)
I made this code to transform django models into pydantic models, but I'm getting an async error
def to_schema(schema: type[Schema], model: type[models.Model]):
async def load_field(obj, field):
print("LOADING FIELD", field.name)
await sync_to_async(lambda: getattr(obj, field.name))()
async def load_many(obj, field):
print("LOADING MANY", field.name)
res = await sync_to_async(list)(getattr(obj, field.name).all())
getattr(obj, field.name)
return res
def get_field_type(field_info):
type = field_info.annotation
if typing.get_origin(type) is list:
type = type.__args__[0]
return getattr(type, "model_fields", type)
async def load(obj, model_, fields):
print(fields)
print(type(fields))
if not isinstance(fields, dict):
return
fields_to_prefetch = [
field for field in model_._meta.get_fields() if field.is_relation
]
for field in fields_to_prefetch:
if field.name in fields:
if field.one_to_one or field.many_to_one:
await load_field(obj, field)
await load(
getattr(obj, field.name),
model_=field.related_model,
fields=get_field_type(fields[field.name]),
)
else:
for obj_ in await load_many(obj, field):
await load(
obj_,
field.related_model,
get_field_type(fields[field.name]),
)
def inner(func: Callable[..., Any]):
@wraps(func)
async def wrapper(*args: Any, **kwargs: Any):
res = await func(*args, **kwargs)
fields_to_prefetch = [
field for field in model._meta.get_fields() if field.is_relation
]
for field in fields_to_prefetch:
if field.name in schema.model_fields:
if isinstance(res, list):
for obj in res:
await load_field(obj, field)
await load(
getattr(obj, field.name),
field.related_model,
get_field_type(schema.model_fields[field.name]),
)
else:
await load_field(res, field)
await load(
getattr(res, field.name),
field.related_model,
get_field_type(schema.model_fields[field.name]),
)
return res
return wrapper
return inner
but I am getting this error
{'type': 'get_attribute_error', 'loc': ('response', 'pack', 'config', 'exclude_collections'), 'msg': 'Error extracting attribute: SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.', 'input': <DjangoGetter: <FutPackConfig: a Config>>, 'ctx': {'error': 'SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.'}}
{'type': 'get_attribute_error', 'loc': ('response', 'pack', 'config', 'only_cards'), 'msg': 'Error extracting attribute: SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.', 'input': <DjangoGetter: <FutPackConfig: a Config>>, 'ctx': {'error': 'SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.'}}
{'type': 'get_attribute_error', 'loc': ('response', 'pack', 'config', 'exclude_cards'), 'msg': 'Error extracting attribute: SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.', 'input': <DjangoGetter: <FutPackConfig: a Config>>, 'ctx': {'error': 'SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.'}}
{'type': 'get_attribute_error', 'loc': ('response', 'pack', 'config', 'only_teams'), 'msg': 'Error extracting attribute: SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.', 'input': <DjangoGetter: <FutPackConfig: a Config>>, 'ctx': {'error': 'SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.'}}
They are all many to many relationships
however it uses .all() to load, should I use something else?
That's a whole lot of code. I suggest you reduce it to the bare minimum where the error happens.
supposedly all should be usable in an async context, but you could probably move it in sync_to_async.
I don't get the sync_to_async(list) though
res = await sync_to_async(getattr(obj, field.name).all)()
P.S. I've never truly used async beyond experiments, so take this with a grain of salt.
the error occurs in many to many relationships,
for example user.houses
it gives an async error because it is a many to many relationship, even though I have already done an .all() before...
The error occurs when trying to transform django's models.Model to pydantic.BaseModel, because for some reason it is not saving .all() that I did previously...
I tried to find something about this in django ninja, but I didn't find anything
:v
Sorry, can't be of more help, I truly hope you solve your problem!
thanks
.
Hi @raven ferry , I am just curious what's the reason you paired fastApi with Django for ?
I'm part of a project, and there are some GMs who are not programmers, so the django admin panel would help a lot for them to do a CRUD, and I used it together with fastapi because it's a framework that I already have experience with and I have code that I can reuse
(but you are aware that drf and django-ninja exists?)
yes