Избегание множественных ссылок на один и тот же объект в Django ORM

У нас есть приложение с сильно взаимосвязанными данными, то есть во многих случаях два объекта могут ссылаться на один и тот же объект через отношения. Насколько я могу судить, 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 (и помогает сократить пропускную способность БД), однако по-прежнему существует проблема сопоставления нескольких экземпляров с одной и той же базовой моделью даже при наличии этих мер.

7
задан glenc 18 January 2012 в 17:11
поделиться