Запрос истории¶
Запрос истории по экземпляру модели¶
Объект HistoricalRecords
на экземпляре модели может быть использован так же, как и менеджер модели:
>>> from polls.models import Poll, Choice
>>> from datetime import datetime
>>> poll = Poll.objects.create(question="what's up?", pub_date=datetime.now())
>>>
>>> poll.history.all()
[<HistoricalPoll: Poll object as of 2010-10-25 18:03:29.855689>]
При сохранении экземпляра модели создается новая историческая запись:
>>> poll.pub_date = datetime(2007, 4, 1, 0, 0)
>>> poll.save()
>>> poll.history.all()
[<HistoricalPoll: Poll object as of 2010-10-25 18:04:13.814128>, <HistoricalPoll: Poll object as of 2010-10-25 18:03:29.855689>]
Запрос истории по классу модели¶
Исторические записи для всех экземпляров модели можно запросить, используя менеджер HistoricalRecords
для класса модели. Например, исторические записи для всех экземпляров Choice
могут быть запрошены с помощью менеджера для класса модели Choice
:
>>> choice1 = poll.choice_set.create(choice_text='Not Much', votes=0)
>>> choice2 = poll.choice_set.create(choice_text='The sky', votes=0)
>>>
>>> Choice.history
<simple_history.manager.HistoryManager object at 0x1cc4290>
>>> Choice.history.all()
[<HistoricalChoice: Choice object as of 2010-10-25 18:05:12.183340>, <HistoricalChoice: Choice object as of 2010-10-25 18:04:59.047351>]
Поскольку история является моделью, вы также можете фильтровать ее как обычные QuerySets, например, Choice.history.filter(choice_text='Not Much')
будет работать!
Получение предыдущей и следующей исторической записи¶
Если у вас есть историческая запись для экземпляра и вы хотите получить предыдущую историческую запись (более старую) или следующую историческую запись (более новую), можно использовать атрибуты prev_record и next_record, предназначенные только для чтения, соответственно.
>>> from polls.models import Poll, Choice
>>> from datetime import datetime
>>> poll = Poll.objects.create(question="what's up?", pub_date=datetime.now())
>>>
>>> record = poll.history.first()
>>> record.prev_record
None
>>> record.next_record
None
>>> poll.question = "what is up?"
>>> poll.save()
>>> record.next_record
<HistoricalPoll: Poll object as of 2010-10-25 18:04:13.814128>
Если историческая запись является первой записью, prev_record будет None. Аналогично, если это последняя запись, next_record будет None.
Изменение модели¶
SimpleHistoryAdmin
позволяет пользователям вернуться к старой версии модели через интерфейс администратора. Вы также можете сделать это программно. Для этого можно взять любой исторический объект и сохранить связанный с ним экземпляр. Например, если мы хотим получить доступ к самому раннему HistoricalPoll
, для экземпляра Poll
, мы можем сделать следующее:
>>> poll.history.earliest()
<HistoricalPoll: Poll object as of 2010-10-25 18:04:13.814128>
И чтобы вернуться к этому экземпляру HistoricalPoll
, мы можем сделать следующее:
>>> earliest_poll = poll.history.earliest()
>>> earliest_poll.instance.save()
Это изменит экземпляр poll
на данные из объекта HistoricalPoll
и создаст новую строку в таблице HistoricalPoll
, указывающую на то, что было сделано новое изменение.
как_из¶
Этот метод возвращает экземпляр модели в том виде, в котором она существовала бы на указанную дату и время.
>>> from datetime import datetime
>>> poll.history.as_of(datetime(2010, 10, 25, 18, 4, 0))
<Poll: Poll object as of 2010-10-25 18:03:29.855689>
>>> poll.history.as_of(datetime(2010, 10, 25, 18, 5, 0))
<Poll: Poll object as of 2010-10-25 18:04:13.814128>
самый_поздний¶
Этот метод возвращает последнюю копию модели, доступную в истории модели.
>>> from datetime import datetime
>>> poll.history.most_recent()
<Poll: Poll object as of 2010-10-25 18:04:13.814128>
Сохранить без исторической записи¶
Если вы хотите сохранить модель без исторической записи, вы можете использовать следующее:
class Poll(models.Model):
question = models.CharField(max_length=200)
history = HistoricalRecords()
def save_without_historical_record(self, *args, **kwargs):
self.skip_history_when_saving = True
try:
ret = self.save(*args, **kwargs)
finally:
del self.skip_history_when_saving
return ret
poll = Poll(question='something')
poll.save_without_historical_record()
Фильтрация данных с использованием связи с моделью¶
Для фильтрации изменений в данных можно установить связь с историей. Например, все записи данных, в которых участвовал определенный пользователь.
class Poll(models.Model):
question = models.CharField(max_length=200)
log = HistoricalRecords(related_name='history')
Poll.objects.filter(history__history_user=4)
Вы также можете выполнить предварительную выборку объектов с этим отношением, используя что-то вроде этого, например, для предварительной выборки в порядке убывания по history_date:
Poll.objects.filter(something).prefetch_related(Prefetch('history', queryset=Poll.history.order_by('-history_date'),
to_attr='ordered_histories')