Определите, был ли объект, связанный с Django, предварительно получен с помощью select_related

Допустим, у меня есть следующие модели:

class Product:
    name = models.CharField(max_length=128)

class ProductVersion:
    name = models.CharField(max_length=128)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)

Для данного объекта ProductVersion можно ли как-то определить, был ли объект Product префетчен через select_related? Например:

# Yes, "product" was prefetched
ProductVersion.objects.select_related("product").first()

# No, "product" was NOT prefetched
ProductVersion.objects.first()

Похоже, что есть способ сделать это для prefetch_related (см. здесь), но мне это нужно для selected_related.

Вы можете сделать это с помощью проверки JOIN слова в запросе

queryset = ProductVersion.objects.select_related("product")
sql_query = str(queryset.query) # convert ORM query to SQL query
if 'JOIN' in sql_query:
    print("Product object was prefetched via select_related")
else:
    print("Product object was NOT prefetched via select_related")

Нет специального способа проверить, было ли поле заполнено благодаря select_related, но если ваша цель - проверить, приведет ли обращение к полю к запросу к базе данных, вы можете проверить, кэшировано поле или нет, используя метод is_cached на его дескрипторе:

cached_obj = ProductVersion.objects.select_related("product").first()
noncached_obj = ProductVersion.objects.first()


print(ProductVersion.product.is_cached(cached_obj)) # True
# OR in case you don't want to use the model class directly
print(cached_obj._meta.model.product.is_cached(cached_obj)) # True

print(ProductVersion.product.is_cached(noncached_obj)) # False
# OR in case you don't want to use the model class directly
print(noncached_obj._meta.model.product.is_cached(noncached_obj)) # False
Вернуться на верх