Хранение истории редактирования модели Django в другой пользовательской модели
У меня есть две модели, скажем:
class superfields(Model):
fieldA = models.FloatField()
fieldB = models.FloatField()
class Meta:
abstract = True
class my_model( superfields ):
def has_history( self ):
return self.my_model_history_set.count() > 0
class my_model_history( superfields ):
reason = models.TextField()
mymodel = models.ForeignKey( my_model )
'my_model' заполняется данными (в полях A и fieldB). Всякий раз, когда кто-то редактирует поля my_model и сохраняет их, я не хочу сохранять изменения в этой модели, но хочу сохранить их как новую строку со всеми значениями в my_model_history, в дополнение к полю 'reason', в то время как my_model ' данные остаются прежними.
Как лучше всего подойти к этому сценарию с точки зрения пользовательских шаблонов, пользовательских представлений, администраторов моделей и т. Д. И т. Д. Я делаю это правильно?
Чтобы придать моему вопросу некоторый смысл, в моем проекте характер данных "my_model" - это рыночные цены, и мне нужно вести историю всех рыночных цен, когда-либо отредактированных, с "причиной" для редактирования.
3 ответа
Мое решение:
да. Вот простое и быстрое решение, которому я следую: я создаю три модели, подобные этой:
class my_super_abstract_model(Model):
#All fields I need to keep a history for:
fieldA = models.FloatField()
fieldB = models.FloatField()
class Meta:
abstract = True
class my_model( my_super_abstract_model ):
def has_history( self ):
return self.my_model_history_set.count() > 0
class my_model_history( my_super_abstract_model ):
reason = models.TextField()
history_entry_for = models.ForeignKey( my_model )
Я настроил сигнал:
pre_save.connect( create_history,
sender = my_model_history )
и 'create history' для вызова по сигналу pre_save() перед сохранением в my_model_history:
def create_history(sender, **kwargs):
#get variables passed by the pre-save signal:
history_model = kwargs['instance']
# Get main model object
main_model = history_model.history_entry_for
# swap all common fields between history edit and main model (except id)
main_model_fields = [f.name for f in main_model._meta.fields]
history_model_fields = [f.name for f in history_model._meta.fields]
field_index = list( [f for f in history_model_fields if f in main_model_fields and f != 'id' and f != 'created_date' ] )
#loop thru to swap values:
for field_name in field_index:
temp = getattr(main_model, field_name)
setattr( main_model, field_name, getattr( history_model, field_name ) )
setattr( history_model, field_name, temp)
# After the swap, save main model object here
main_model.save()
Всякий раз, когда пользователь щелкает строку my_model для редактирования, я использую my_model_history, чтобы сгенерировать форму редактирования и заполнить ее значениями из выбранной пользователем строки. (Написали вид и шаблон для этого)
Таким образом, форма редактирования теперь будет иметь:
- поле A заполнено значениями из строки данных my_model
- поле B заполнено значениями из строки данных my_model
- Причина - пустое текстовое поле
- history_entry_for - скрыто от глаз
Пользователь теперь может редактировать fieldA/fieldB. Введите причину. Нажмите сохранить, чтобы активировать сигнал выше. Перед сохранением,
- Сигнал поменяет местами значения между основной моделью (старые значения) и исторической моделью (новые значения)
- Замените и сохраните основной ряд модели (с новыми значениями).
- Вставьте и сохраните новую строку в исторической модели (со старыми значениями) с указанием причины.
Надеюсь, поможет. Дайте мне знать, если есть еще вопросы.
Вместо того, чтобы редактировать существующую запись, почему бы не использовать эту запись в качестве начальных данных для формы для создания нового экземпляра? Новый объект сохраняется, оригинал остается прежним...
Я нашел объяснение о том, как хранить подробные истории редактирования в книге "pro Django", на странице 264. После прочтения я попробую реализовать то, что мне нужно. Опубликую мой подход здесь, когда я закончу