История моделей в Django
Это своеобразный вопрос, который был задан ранее, но не совсем охватывающий те же самые вопросы. Я прочитал эти (Вопрос, Вопрос, Вопрос , и вопрос), но вопрос немного отличается.
У меня есть модель записи в блоге (псевдокод для скорости), которая содержит заголовок, аннотацию и тело, а также связанные с ними изображения.class Post(models.Model):
title = CharField
abstract = TextField
body = TextField
class Image(models.Model):
post = ForeignKey(Post)
imagefile = ImageField
Теперь я хочу добавить возможность хранить истории изменений в этом Post
модель. Я подумал о двух возможностях для этого:
Возможность 1
class PostHistory(models.Model):
post = ForeignKey(Post)
title_delta = TextField
abstract_delta = TextField
body_delta = TextField
Однако это имеет проблему, что он хранит дельты без изменений (например, когда title
не изменяется, и есть только Дельта для поля body
. Тем не менее, когда изменяется более одного поля, это соответствует тому, что "1 ревизия == 1 полная ревизия".
Возможность 2
class PostRevision(models.Model):
post = ForeignKey(Post)
field = CharField #Field name
delta = TextField
Благодаря двум различным подходам это успешно дает мне историю различий для поля, которое я бы сгенерировал с помощьюdiff-match-patch (немного более производительный, чем встроенныйdifflib ). Два вопроса, которые я сейчас имею, связаны с генерацией основных объектов (т. е. с верхней ревизией в цепочке).
Задается вопрос, как мне тогда справиться с одновременными изменениями изображений, связанных с объектом Post, поскольку они будут изменены через ссылки в поле body
Модели Post
(это форматированный текст Markdown поле, которое затем редактируется на POST
формы, чтобы добавить в URL ссылки для поля изображения. Является ли лучшим способом справиться с этим, чтобы использовать поле M2M на ревизии и на объекте Post
, позволяя всегда сохранять изображения с объектом PostRevision
?
2 ответа:
Я согласен с @rickard-zachrisson, что вы должны придерживаться подхода №1. Я бы сделал несколько тонких изменений, хотя (псевдокод кстати):
class AbstractPost(models.Model): title = CharField abstract = TextField body = TextField class Meta: abstract = True class Post(AbstractPost): def save(self): post = super(Post, self).save() PostHistory.objects.create( post=post, title=post.title, abstract=post.abstract, body=post.body, ) class PostHistory(AbstractPost): post = ForeignKey(Post) class Meta: ordering = ['-pk'] class Image(models.Model): post = ForeignKey(Post) imagefile = ImageField
Ваша последняя версия всегда будет находиться в
Post
, а история изменений-вpk
порядкеPostHistory
, который легко отличить от изменений. Я бы дублировал данные, потому что хранение дешево, а хранение дельт-это Пита. Если у вас есть несколько правок или вы хотите сравнить текущую версию с оригинальной версией, то дельты в основном бесполезны. Какой-нибудь изменения модели в AbstractPost отражены как вPost
, так и вPostHistory
.
Image
он настроен на пост, чтобы вещи оставались аккуратными. Вы можете дополнительно очистить изображения в своем посте.функция save (), но я бы, вероятно, выбрал сигнал post_save, чтобы сохранить код чище.
Я думаю, вам следует придерживаться варианта 1.
Идея состояла бы в том, чтобы иметь автоматизированную систему пересмотра. Вот как я буду делать и возражать против некоторых синтаксических ошибок, я печатаю из моей головы
class A(models.Model): field1 = ... field2 = ... def save(): if bla_bla_updated: A_revisions.objects.create( field1=self.fields1, field2=self.fields2, a=self) super(A, self).save() class A_revision(models.Model): field1 = ... field2 = ... a = models.ForeignKey(A) revision = models.IntegerField() def save(): self.revision = (A_revision.objects.get(a=self.a) .order_by('id').revision) + 1 super(A_revision, self).save()