Маючи цю проблему та знайшовши два остаточні рішення для неї, я вважав, що варто опублікувати ще одну відповідь.
Це проблема із стандартним режимом транзакцій MySQL. Django відкриває транзакцію на початку, це означає, що за замовчуванням ви не побачите змін, внесених до бази даних.
Демонструйте так
Запустіть оболонку django у терміналі 1
>>> MyModel.objects.get(id=1).my_field
u'old'
І ще один в терміналі 2
>>> MyModel.objects.get(id=1).my_field
u'old'
>>> a = MyModel.objects.get(id=1)
>>> a.my_field = "NEW"
>>> a.save()
>>> MyModel.objects.get(id=1).my_field
u'NEW'
>>>
Повернімось до терміналу 1, щоб продемонструвати проблему - ми все ще читаємо старе значення з бази даних.
>>> MyModel.objects.get(id=1).my_field
u'old'
Тепер у терміналі 1 продемонструйте рішення
>>> from django.db import transaction
>>>
>>> @transaction.commit_manually
... def flush_transaction():
... transaction.commit()
...
>>> MyModel.objects.get(id=1).my_field
u'old'
>>> flush_transaction()
>>> MyModel.objects.get(id=1).my_field
u'NEW'
>>>
Тепер нові дані зчитуються
Ось цей код у простому для вставлення блоці за допомогою docstring
from django.db import transaction
@transaction.commit_manually
def flush_transaction():
"""
Flush the current transaction so we don't read stale data
Use in long running processes to make sure fresh data is read from
the database. This is a problem with MySQL and the default
transaction mode. You can fix it by setting
"transaction-isolation = READ-COMMITTED" in my.cnf or by calling
this function at the appropriate moment
"""
transaction.commit()
Альтернативне рішення - змінити my.cnf для MySQL на режим транзакцій за замовчуванням
transaction-isolation = READ-COMMITTED
Зверніть увагу, що це відносно нова функція для Mysql і має деякі наслідки для двійкового журналювання / підпорядкування . Ви також можете помістити це в преамбулу підключення django, якщо хочете.
Оновлення через 3 роки
Тепер, коли Django 1.6 увімкнув автозв'язок у MySQL, це вже не проблема. Наведений вище приклад тепер чудово працює без flush_transaction()
коду, чи перебуває ваш MySQL REPEATABLE-READ
(за замовчуванням) або в READ-COMMITTED
режимі ізоляції транзакцій.
У попередніх версіях Django, які працювали в режимі, що не виконується автоматично, те, що перший select
оператор відкривав транзакцію, відбувався . Оскільки режим MySQL за замовчуванням такий, REPEATABLE-READ
це означає, що жодні оновлення бази даних не будуть прочитані наступними select
операторами - отже, необхідність у flush_transaction()
коді, який вище зупиняє транзакцію та запускає нову.
Однак існують причини, чому ви можете використовувати READ-COMMITTED
ізоляцію транзакцій. Якщо ви хочете помістити термінал 1 у транзакції, і ви хочете побачити записи з терміналу 2, вам знадобиться READ-COMMITTED
.
Тепер flush_transaction()
код видає попередження про припинення використання в Django 1.6, тому я рекомендую вам його видалити.