Перезавантажте об'єкт django з бази даних


160

Чи можливо оновити стан об'єкта django з бази даних? Я маю на увазі поведінку, приблизно еквівалентну:

new_self = self.__class__.objects.get(pk=self.pk)
for each field of the record:
    setattr(self, field, getattr(new_self, field))

ОНОВЛЕННЯ: В трекері знайдено війну, що відкрилася / повторилася: http://code.djangoproject.com/ticket/901 . Досі не розумію, чому технічному обслуговуванню це не подобається.


У звичайному контексті SQL це не має сенсу. Об'єкт бази даних може бути змінений лише після завершення транзакції та виконання commmit. Після цього вам доведеться почекати наступної транзакції SQL. Навіщо це робити? Як довго ви будете чекати наступної транзакції?
S.Lott

Це здається непотрібною функцією; вже можна просто переглянути об’єкт із бази даних.
Стефан

я хотів би , як добре, але вона була закрита кілька разів тут
eruciform

2
Це не доречно, оскільки об'єкти моделі Джанго - це проксі. Якщо ви отримуєте однаковий рядок таблиці на два об’єкти - x1 = X.objects.get (id = 1); x2 = X.objects.get (id = 1), вони перевіряться рівними, але вони є різними об'єктами, і стан не поділяється. Ви можете змінити обидва незалежно та зберегти їх - останній збережений визначає стан рядка в базі даних. Тому правильно перезавантажити простим завданням - x1 = X.objects.get (id = 1). Наявність методу перезавантаження призведе до того, що багато людей помилково роблять висновок, що x1.f = 'нове значення'; (x1.f == x2.f) - Істинно.
Пол Віпп

Відповіді:


259

Станом на Django 1.8 вбудовані освіжаючі об'єкти. Посилання на документи .

def test_update_result(self):
    obj = MyModel.objects.create(val=1)
    MyModel.objects.filter(pk=obj.pk).update(val=F('val') + 1)
    # At this point obj.val is still 1, but the value in the database
    # was updated to 2. The object's updated value needs to be reloaded
    # from the database.
    obj.refresh_from_db()
    self.assertEqual(obj.val, 2)

@ fcracker79 Так, це було реалізовано лише у 1.8. У більш ранніх версіях Джанго вам найкраще відповісти на одну з інших відповідей.
Тім Флетчер

1
Не впевнені, що означає "Усі відкладені поля оновлені", зазначені в документах?
Юнті

1
@Yunti Ви можете відкласти поля або явно запитати лише підмножину полів, і отриманий об'єкт буде лише частково заповнений. refresh_from_dbбуде оновлювати лише такі вже заповнені поля.
301_Moved_Постійно

Не вдалося знайти деталі в документах, але він належним чином викидає DoesNotExistвиняток, якщо базовий об'єкт був видалений під час виклику refresh_from_db. FYI.
Тім Тісдалл

28

Я вважаю, що відносно легко перезавантажити об'єкт із бази даних так:

x = X.objects.get(id=x.id)

19
Так, але ... після цього ви повинні оновити всі посилання на цей об’єкт. Не дуже зручна і схильна до помилок.
греп

2
Виявив це необхідним, коли Селері оновив мій об’єкт у db за межами django, django, очевидно, зберігав кеш об'єкта, оскільки він не мав уявлення, що він змінився.
Боб Сприн

3
з django.db.models.loading import get_model; instance = get_model (instance) .objects.get (pk = instance.pk)
Ерік

1
@grep щойно втратив 2 години, написавши тест для цього випадку використання: 1: ініціалізувати модель; 2: оновіть модель за допомогою форми; 3: Перевірте, чи нове значення оновлено .... Так, так, до помилок.
vlad-ardelean

3
Я думаю, що refresh_from_dbвирішує всі ці проблеми.
Flimm

16

Посилаючись на коментар @ grep, чи не можна це робити:

# Put this on your base model (or monkey patch it onto django's Model if that's your thing)
def reload(self):
    new_self = self.__class__.objects.get(pk=self.pk)
    # You may want to clear out the old dict first or perform a selective merge
    self.__dict__.update(new_self.__dict__)

# Use it like this
bar.foo = foo
assert bar.foo.pk is None
foo.save()
foo.reload()
assert bar.foo is foo and bar.foo.pk is not None

Дякую за рішення. Якби тільки ТАК дозволяв кілька голосів!
користувач590028

11
Тепер Джанго надає refresh_from_dbметод.
Flimm

9

Як зазначав @Flimm, це дійсно приголомшливе рішення:

foo.refresh_from_db()

Це перезавантажує всі дані з бази даних в об’єкт.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.