Как Django узнает о существовании объекта
Допустим, у меня есть две модели, например:
class Product:
product_name = models.CharField(max_length=40)
class ProductPrice(models.Model):
product = models.OneToOneField(Product, on_delete=models.CASCADE)
product_price = models.FloatField()
Пожалуйста, не беспокойтесь о том, почему кому-то могут понадобиться две разные модели/таблицы для таких данных. Это не главное здесь. Что интересно, когда я запрашиваю Product
, я получу python attr productprice
вместе с объектом ТОЛЬКО ЕСЛИ ProductPrice
существуют связанные с этим Product
.
Чтобы сделать это более понятным, давайте создадим некоторые фиктивные данные:
product1 = Product.objects.create(product_name='first product')
product2 = Product.objects.create(product_name='second product')
product_price = ProductPrice.objects.create(product=product2, price=10.99)
Теперь попробуйте это
print(hasattr(product1`, "productprice")) # -> false
print(hasattr(product2`, "productprice")) # -> true
Как django узнает о существовании ProductPrice
в базе данных? В SQL я не знаю никакого способа проверить это без второго запроса. Мне очень интересно, как это работает.
Как django узнает, что ProductPrice существует в базе данных?
Выполняет SQL-запрос. Действительно, он отслеживает все отношения и определяет для каждого отношения одно в противоположном направлении. Это свойства, которые являются лениво загруженными.
Это означает, что если вы используете hasattr(product1, 'productprice')
, то запрос будет выглядеть следующим образом:
SELECT appname_productprice.*
FROM appname_productprice
WHERE appname_productprice.product_id = some_id
В случае если запрос вернет запись, он вернет True
для этого атрибута, в случае если база данных не вернет ни одной записи, это вызовет ошибку AttributeError
, и таким образом hasattr(…)
вернет False
.
Таким образом, эти запросы выполняются лабильно: только когда вы обращаетесь к атрибуту .productprice
, он будет делать такой запрос, пока вы не обращаетесь к этому атрибуту, запрос не выполняется.
Если мы, например, посмотрим на последний запрос, который Django выполняет с помощью print(connection.queries[-1])
, мы увидим:
>>> from django.db import connection
>>> print(hasattr(product1, 'productprice'))
False
>>> print(connection.queries[-1])
{'sql': 'SELECT `appname_productprice`.`id`, `appname_productprice`.`product_id`, `appname_productprice`.`product_price` FROM `appname_productprice` WHERE `appname_productprice`.`product_id` = 1 LIMIT 21', 'time': '0.001'}
>>> print(hasattr(product2, 'productprice'))
True
>>> print(connection.queries[-1])
{'sql': 'SELECT `appname_productprice`.`id`, `appname_productprice`.`product_id`, `appname_productprice`.`product_price` FROM `appname_productprice` WHERE `appname_productprice`.`product_id` = 2 LIMIT 21', 'time': '0.001'}