История моделей в Джанго

Это разновидность вопроса, который был задан ранее, но не совсем охватывает те же вопросы. Я прочитал их ( вопрос, вопрос, вопрос и вопрос), но проблема немного отличается.

У меня есть модель поста в блоге (псевдокод для скорости), которая содержит заголовок, реферат и текст, а также связанные изображения.

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()
Другие вопросы по тегам