Хранение истории редактирования модели 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, чтобы сгенерировать форму редактирования и заполнить ее значениями из выбранной пользователем строки. (Написали вид и шаблон для этого)

Таким образом, форма редактирования теперь будет иметь:

  1. поле A заполнено значениями из строки данных my_model
  2. поле B заполнено значениями из строки данных my_model
  3. Причина - пустое текстовое поле
  4. history_entry_for - скрыто от глаз

Пользователь теперь может редактировать fieldA/fieldB. Введите причину. Нажмите сохранить, чтобы активировать сигнал выше. Перед сохранением,

  1. Сигнал поменяет местами значения между основной моделью (старые значения) и исторической моделью (новые значения)
  2. Замените и сохраните основной ряд модели (с новыми значениями).
  3. Вставьте и сохраните новую строку в исторической модели (со старыми значениями) с указанием причины.

Надеюсь, поможет. Дайте мне знать, если есть еще вопросы.

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

Я нашел объяснение о том, как хранить подробные истории редактирования в книге "pro Django", на странице 264. После прочтения я попробую реализовать то, что мне нужно. Опубликую мой подход здесь, когда я закончу

Другие вопросы по тегам