История моделей в Джанго
Это разновидность вопроса, который был задан ранее, но не совсем охватывает те же вопросы. Я прочитал их ( вопрос, вопрос, вопрос и вопрос), но проблема немного отличается.
У меня есть модель поста в блоге (псевдокод для скорости), которая содержит заголовок, реферат и текст, а также связанные изображения.
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-файлов для поля, которую я бы сгенерировал, используя 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
ключ к сообщению, чтобы все оставалось в порядке. Вы можете при желании очистить изображения в вашей функции Post.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()