Внешние ключи и метод сохранения в Django - PullRequest
4 голосов
/ 10 сентября 2011

У меня есть следующая модель:

class A:
  b = ForeignKey('B')

class B:
  a = ForeignKey('A', null=True)

У меня есть несколько методов, которые декодируют объект json и создают дерево объектов A и B. Предположим, у меня есть объект типа A, который я хочу сохранить, я пытаюсь написать что-то вроде этого

в классе А:

def save(self, *args, **kwargs):
  self.b.save()
  super(A, self).save(*args, **kwargs)

в B:

def save(self, *args, **kwargs):
  if self.a:
    self.a.save()
  super(B, self).save(*args, **kwargs)

Это не работает, хотя A.b и B.a получают идентификатор при вызове save (), они все же нарушают ненулевое ограничение в A. Я где-то читал, что это связано с тем, как работает ORM и как объекты кешируются каким-либо образом.

Предложенное решение заключалось в следующем:

a = A()
b = B()
b.save()
a.b = b
a.save()

Но по очевидной причине рекурсии это не подходит в моем случае. Поэтому единственное, что я могу обойти, - это предоставить каждому объекту метод, который рекурсивно извлекает каждый объект, который необходимо сохранить, а затем выполнить цикл for, чтобы сохранить каждый объект в правильном порядке. Я действительно хотел бы избежать этого, поскольку, конечно, фактическая модель более сложна и включает в себя более двух классов и более одного внешнего ключа на класс.

Так что, я думаю, мой вопрос прост: есть ли лучший способ или более распространенный способ действовать в таких ситуациях?

Ответы [ 2 ]

2 голосов
/ 11 сентября 2011

Ну, после некоторого поиска души, я обнаружил, что это действительно «проблема» кеша.У меня нет времени, чтобы заглянуть внутрь кода django, чтобы понять, как все на самом деле работает, поэтому, если у кого-то есть какие-то интересные идеи, которые были бы великолепны.

Тем временем я нашел решение - заставить объекточистить кэш следующим образом:

def save(self, *args, **kwargs):
  self.b.save()
  self.b = self.b # yes ...
  super(A, self).save(*args, **kwargs)

Это работает, но для записи есть небольшой помощник, который автоматически очищает кэш перед любым сохранением:

def clear_cache(obj):
  map(lambda x: obj.__setattr__(x, obj.__getattribute__(x)), \ # force reassignment
    map(lambda x: re.match('_(.*)_cache', x).groups()[0], \    # get attribute name
    filter(lambda x: x.find('_cache') != -1, dir(obj))))       # get all attribute with cache

@receiver(pre_save)
def cache_callback(sender, instance, **kwargs):
  clear_cache(instance)
0 голосов
/ 10 сентября 2011

Стоит отметить, что вы делаете сохранение других объектов до того, как вы вызываете метод сохранения суперкласса, который, вероятно, противоположен тому, что вы хотите.

В качестве альтернативы, ив конечном итоге это может стать чище, используйте сигналы после сохранения .

...