2014-09-19 4 views
0

Я ищу способ обновления нескольких объектов более эффективно, чем вызов .save() на каждом из них.Как сохранить объекты навалом с помощью django 1.6

У меня есть код, который использует .filter() для загрузки объектов. Затем он связывается с внешней службой, чтобы решить, что нужно делать с каждым объектом. Наконец, у меня есть список объектов с обновленными значениями, которые мне нужно сохранить.

Этот код работает, но слишком медленно:

for o in l: o.save() 

Поиск предложений, которые я до сих пор нашел .bulk_create() и .update()

bulk_create отлично работает для новых объектов. Но замена выше цикла на model.objects.bulk_create(l) дает IntegrityError: UNIQUE constraint failed:, вероятно, потому, что он пытается создавать новые объекты, а не обновлять существующие объекты.

Использование .update() также не применимо к моему прецеденту, так как оно обновит все объекты в наборе с тем же значением. В моем случае я вычислил другое значение для каждого из объектов, которые мне нужно сохранить.

Есть ли более быстрое решение, чем вызов .save() на каждый объект?

ответ

0

Вы можете попробовать установить флаг has_changed в объект при его изменении, а затем сохранить объекты, в которых has_changed имеет значение True.

Это связано с тем, что не все объекты всегда изменяются. Если все объекты всегда меняются, это не решение.

+0

Я не называю 'save' на всех объектах, которые я получил. Я просматриваю все объекты, выполняя некоторые вычисления в памяти. Те объекты, которые изменены этим вычислением, присоединяются к новому списку. Список, который я хочу сохранить в конце, содержит только те объекты, которые были изменены. – kasperd

+0

ahhh, хорошо, я буду обдумывать это в глубине моего разума. – mdw7326

0

Django не может этого сделать, потому что (в общем) ваша база данных не может этого сделать. Нет единого оператора SQL для обновления разных строк с разными значениями. (Особые исключения, такие как использование CASE...WHEN, вряд ли помогут здесь.)

Если многие или большинство объектов были новыми, вы можете отслеживать, какие и создавать их с помощью bulk_create; в противном случае, итерация и выполнение save(), вероятно, лучший выбор.

Возможно, вы планируете распараллеливать процедуру с помощью потоков, особенно если существует значительная латентность, связанная с внешней службой.

+0

Возможно, это не обязательно должен быть один оператор SQL. Отправка нескольких операторов SQL назад и отсрочка обработки ответов может быть намного быстрее, чем обработка их полностью последовательной. – kasperd

+0

Любая причина, по которой django не может иметь общий метод 'bulk_save', основанный на' CASE WHEN', как описано здесь: http: // stackoverflow.com/a/20255203/3476849 – kasperd

0

Я нашел обходной путь:

class CASE(object): 
    def __init__(self, field_name, objects): 
     self.field_name = field_name 
     self.objects = objects 

    def __unicode__(self): return self 

    def as_sql(self, qn, connection): 
     sql = [ 'CASE id' ] 
     params = [] 
     for o in self.objects: 
      sql.append('WHEN %s THEN %s') 
      params.append(o.pk) 
      params.append(getattr(o, self.field_name)) 
     sql.append('ELSE') 
     sql.append(qn(self.field_name)) 
     sql.append('END') 
     return (' '.join(sql), params) 

model.objects.update(value=CASE('value', l)) 

Это не очень, но, насколько я могу судить, это действительно производит правильный и эффективный SQL до тех пор, как я просто обновление одного текстового поля.

+0

Я чувствую, что не должен принимать свой собственный ответ, потому что он настолько узкий, что, хотя это может быть подходящим обходным путем для моего конкретного случая, он не отвечает на общую версию вопроса, поскольку Я это сказал. Чтобы достичь этого, он, по крайней мере, должен автоматически применяться ко всем применимым полям. Также мой обходной способ - это немного взломать. И я предпочел бы полагаться на встроенную функцию, чем на создание собственного метода 'as_sql'. – kasperd

+0

Более чистая реализация вышеуказанного будет использовать 'django.db.models.expressions' вместо моего очень хакерского подхода. – kasperd

 Смежные вопросы

  • Нет связанных вопросов^_^