КонтекстОпределите, если атрибут является `DeferredAttribute` в Джанго
Я расположен довольно критическая ошибка в машине Джанго Cache, который вызывает это недействительности логика потерять свое мнение после обновления с Джанго 1.4 до 1.7.
Исправлена ошибка, связанная с вызовами only()
на моделях, расширяющих кеш-машину CachingMixin
. Это приводит к глубоким рекурсиям, которые иногда ломают стек, но в противном случае создают огромный flush_lists
, который использует кеш-машина для двунаправленной недействительности для моделей в отношениях ForeignKey
.
class MyModel(CachingMixin):
id = models.CharField(max_length=50, blank=True)
nickname = models.CharField(max_length=50, blank=True)
favorite_color = models.CharField(max_length=50, blank=True)
content_owner = models.ForeignKey(OtherModel)
m = MyModel.objects.only('id').all()
Буг
происходит ошибка в следующих строках (https://github.com/jbalogh/django-cache-machine/blob/f827f05b195ad3fc1b0111131669471d843d631f/caching/base.py#L253-L254). В этом случае self
является экземпляром MyModel
с соединением отсроченных и undeferred атрибутов:
fks = dict((f, getattr(self, f.attname)) for f in self._meta.fields
if isinstance(f, models.ForeignKey))
Cache машина делает двунаправленные недействительности через ForeignKey
отношений. Он делает это, перебирая все поля в Model
и сохраняя ряд указателей в кеше, которые указывают на объекты, которые недействительны, когда объект, о котором идет речь, недействителен.
Использование only()
в Django ORM делает некоторую магию программирования мета, которая переопределяет необработанные атрибуты с реализацией Django DeferredAttribute
. При нормальных обстоятельствах доступ к favorite_color
будет вызывать DeferredAttribute.__get__
(https://github.com/django/django/blob/18f3e79b13947de0bda7c985916d5a04e28936dc/django/db/models/query_utils.py#L121-L146) и извлекать атрибут из кеша результатов или источника данных. Он делает это, выбирая необработанное представление вопроса Model
и вызывая на него еще один запрос only()
.
Это проблема при переходе по внешним ключам в Model
и получении доступа к их значениям, Cachine Machine представляет непреднамеренную рекурсию. getattr(self, f.attname)
на атрибут, который отложен, вызывает выборку Model
, которая применяет CachingMixin
и имеет отложенные атрибуты. Это снова запускает весь процесс кэширования.
Вопрос
Я хотел бы открыть PR, чтобы исправить это, и я считаю, что ответ на это так же просто, как пропуск через отсроченные атрибуты, но я не знаю, как сделайте это, потому что доступ к атрибуту заставляет процесс выборки запускаться.
Если все у меня есть ручка на экземпляре Model
со смесью отсроченных и undeferred атрибутов, Есть ли способ определить, если атрибут является DeferredAttribute
без к нему доступ?
fks = dict((f, getattr(self, f.attname)) for f in self._meta.fields
if (isinstance(f, models.ForeignKey) and <f's value isn't a Deferred attribute))
Метод, использующий 'DeferredAttribute', кажется, не работает для меня на Django 1.7.3 ' instance .__ class __.__ dict__' никогда не имеет ключей от регулярных полей. –
@CraynicCai, не уверен, почему он не работает для вас. Этот подход давно использовался Django. Здесь он находится в Django 1.7.3 https://github.com/django/django/blob/1.7.3/django/db/models/base.py#L402 –