Вы можете использовать приведенную ниже функцию для возврата списка предварительно выбираемых полей.
from django.db.models.base import ModelBase
def get_prefetchable_fields(instance):
opts = instance._meta
ret = []
for field in opts.get_fields():
if not isinstance(instance, ModelBase):
rel_obj_descriptor = getattr(instance.__class__, field.name, None)
else:
rel_obj_descriptor = getattr(instance, field.name, None)
if rel_obj_descriptor:
if hasattr(rel_obj_descriptor, 'get_prefetch_queryset'):
ret.append(field.name)
else:
rel_obj = getattr(instance, field.name)
if hasattr(rel_obj, 'get_prefetch_queryset'):
ret.append(field.name)
return ret
Передача модели в функцию вернет список полей ForeignKey
непосредственно в модели, которую можно использовать в prefetch_related
.
prefetchable = get_prefetchable_fields(Child) # ['parent']
fields = ['parent', 'parent_id']
Child.objects.prefetch_related(*[field for field in fields if field in prefetchable])
В качестве бонуса, если вы передадите экземпляр модели, он также вернет связанные поля из другой модели.
instance = Parent.objects.first()
prefetchable = get_prefetchable_fields(instance) # ['child_set']