У нас есть приложение с сильно взаимосвязанными данными, то есть во многих случаях два объекта могут ссылаться на один и тот же объект через отношения. Насколько я могу судить, Django не предпринимает никаких попыток вернуть ссылку на уже извлеченный объект, если вы пытаетесь получить его через другое, ранее не оцененное отношение.
Например:
class Customer( Model ):
firstName = CharField( max_length = 64 )
lastName = CharField( max_length = 64 )
class Order( Model ):
customer = ForeignKey( Customer, related_name = "orders" )
Тогда предположим, что у нас есть один клиент, у которого есть два заказа в БД:
order1, order2 = Order.objects.all()
print order1.customer # (1) One DB fetch here
print order2.customer # (2) Another DB fetch here
print order1.customer == order2.customer # (3) True, because PKs match
print id( order1.customer ) == id( order2.customer ) # (4) False, not the same object
Когда у вас есть сильно взаимосвязанные данные, степень, в которой доступ к отношениям ваших объектов приводит к повторным запросам БД для одних и тех же данных, увеличивается и становится проблемой.
Мы также программируем для iOS, и одна из приятных особенностей CoreData заключается в том, что он поддерживает контекст , так что в данном контексте существует только один экземпляр данной модели. В приведенном выше примере CoreData не выполнила бы вторую выборку в (2), потому что это разрешило бы отношения, используя клиента уже в памяти.
Даже если строка (2) была заменена на ложный пример, предназначенный для принудительного вызова другой выборки из БД (например, print Order.objects.exclude( pk = order1.pk ).get( customer = order1.customer )
), CoreData поймет, что результат этой второй выборки разрешен для модели в памяти, и вместо этого вернет существующую модель. нового (т. е. (4) выведет True в CoreData, потому что на самом деле это будет один и тот же объект).
Чтобы застраховаться от такого поведения Django, мы пишем все эти ужасные вещи, чтобы попытаться кэшировать модели в памяти по их (type, pk)
, а затем проверить отношения с суффиксом _id
, чтобы попытаться извлечь их из кэша до того, как вслепую ударяя по БД с другой выборкой. Это сокращает пропускную способность БД, но кажется действительно хрупким и может вызвать проблемы, если нормальный поиск отношений через свойства случайно происходит в некоторой среде contrib или промежуточном программном обеспечении, которое мы не контролируем.
Существуют ли какие-либо передовые практики или структуры для Django, чтобы помочь избежать этой проблемы? Кто-нибудь пытался установить какой-то локальный контекст потока в ORM Django, чтобы избежать повторных поисков и иметь несколько экземпляров в памяти, сопоставляемых с одной и той же моделью БД?
Я знаю, что кеширование запросов, такое как JohnnyCache, существует (и помогает сократить пропускную способность БД), однако по-прежнему существует проблема сопоставления нескольких экземпляров с одной и той же базовой моделью даже при наличии этих показателей.