Django中的模型历史

时间:2013-01-11 11:04:31

标签: python django django-models version revision-history

这是之前提出过的一个问题,但不完全涵盖同样的问题。我已经仔细阅读了这些内容(questionquestionquestionquestion),但问题略有不同。

我有一个博客文章模型(速度伪代码),其中包含标题,摘要和正文以及相关图像。

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 个答案:

答案 0 :(得分:8)

我同意@ 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的{​​{1}}顺序,这很容易与更改区分开来。我会复制数据,因为存储很便宜并且存储增量是一个皮塔饼。如果您有多个编辑或想要将当前版本与原始版本进行比较,那么增量基本上是无用的。 AbstractPost中的任何模型更改都会反映在PostHistoryPost中。

PostHistory是关键的帖子,所以事情保持整洁。您可以选择清理Post.save()函数中的图像,但我可能会选择post_save信号来保持代码清洁。

答案 1 :(得分:1)

我认为你应该坚持使用选项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()