【问题标题】:Storing hierarchies/trees insdie a django model field?在 Django 模型字段中存储层次结构/树?
【发布时间】:2019-12-18 04:32:32
【问题描述】:

首先,我知道有 django-mptt 和 django-treebeard 之类的软件包,但这些看起来不像我要找的。 (目标似乎是将所有模型实例排列在一棵树中,并且模型具有对每个实例的位置进行编码的字段。只有一棵树,可以重新排列、删除或新插入节点。)


任务:

粗略地说,我的目标是拥有一个存储树木的模型。数据库中要存储多棵树,模型的每个实例都存储其中一棵树。我将尝试说明两个不同复杂度的不同用法示例。第一个可能很容易实现,第二个......我不知道。
[附带问题:我要找的东西有名字吗?搜索 django+tree 导致讨论问题和解决方案,类似于 django-mptt...]


简单案例:

考虑章节和书籍的模型。

class Chapter(Model):
    heading = CharField()
    text = TextField()

class Book(Model):
    name = CharField()
    structure = ???magic???

章节模型存储书籍的文本部分,因此您将有一个实例保存主题 A 的标题和文本,另一个实例保存主题 B,依此类推。书籍模型必须存储书籍的结构,即哪些章节去哪里。一本书有多个章节,一个章节可以出现在多本书中,例如想象两本专门针对同一主题的书籍实例,一本针对初学者,另一本针对专家。虽然这两本书共享一些章节,但它们的结构不同:

Book Beginner
1. Introduction I
2. Topic TA
3. Topic TB
4. Topic TC
Book Expert
1. Topic TA
2. Topic TB
  2.1. Advanced Topic AT1
  2.2. Advanced Topic AT2
    2.2.1 Special Case SCX
3. Topic TC
4. Topic TD

我正在使用 Django、REST 框架和 PostgreSQL。是否存在将书籍的树结构存储在数据库字段中的现有解决方案?如果没有,有什么好的方法来解决它?
我的一个想法是使用 JSONField 并存储包含章节实例主键的嵌套数组,即[I, TA, TB, TC] 用于 book1,[TA, TB, [AT2, AT2, [SCX]], TC, TD] 用于 book2。合理与否?


复杂情况:

(这可能是我真正想要做的。有点类似于上面,但更多元;类似于书籍和章节的合理性也有点崩溃,但我还是会使用它。)

class Paragraph(Model):
    text = TextField()

class ChapterTree(Model):
    structure = ???magic???
    headings = ???magic???

class Book(Model):
    name = CharField()
    chapter_structure = ForeignKey(ChapterTree)
    contents = ???magic???

好的,这一次段落只是一个文本块; ChapterTree 存储章节的布局,但除了可能所有相应的章节标题之外没有文本;一本书必须使用一个预定义的章节结构,并且需要指定哪些段落应该出现在每个章节中。 (即,具有相同章节树的两本印刷书籍总是有相同的目录,但可能有不同的段落作为正文。)考虑,例如,两个不同的章节树和从它们派生的 4 本书:

tree1:                   BookI[chap_s=tree1]:       BookII[chap_s=tree1]:
1. Introduction I        1. Introduction            1. Introduction
2. Topic TA                par1                       par1
3. Topic TB              2. Topic TA                2. Topic TA
                           par2                       par2
                           par3                     3. Topic TB
                         3. Topic TB                  par4
                           par4                       par5
tree2:                       BookIII[chap_s=tree2]:        BookIV[chap_s=tree2]:
1. Topic TA                  1. Topic TA                   1. Topic TA
2. Topic TB                    par2                          par3
  2.1. Advanced AT1          2. Topic TB                   2. Topic TB
  2.2. Advanced AT2            par4                          2.1 Advanced AT1
    2.2.1 Special SCX          2.1 Advanced AT1                par6
                                 par6                          par8
                               2.2. Advanced AT2             2.2. Advanced AT2
                                 2.2.1 Special SCX             par9
                                   par7                        2.2.1 Special SCX
                                                                 par7

对于ChapterTree,我可以尝试同时存储结构和标题,方法是使用包含标题["Introduction I", "Topic TA", "Topic TB"] 用于tree1 和["Topic TA", "Topic TB", ["Advanced AT1", "Advanced AT2", ["Special SCX"]]] 用于tree2 的字符串嵌套数组。然后对于 Book 内容,另一个 JSONField 包含一个数组,其中包含每个级别的段落实例的键数组,例如,四本书将是 [[1], [2, 3], [4]][[1], [2], [4,5]][[2], [4], [6], [], [7]][[3], [], [6,8], [9], [7]]

这个想法很可能很糟糕?没有什么可以强制一致性;例如,如果通过在中间某处添加新的子章节来修改 ChapterTree 实例之一,则使用该树的所有书籍都将被破坏(而不是最终得到一个可以稍后填充的空子章节)。我真的希望有一个更优雅的解决方案。

【问题讨论】:

  • 你研究过图形数据库吗? (这可能会有所帮助)。不使用我认为不能很好地与 Django 集成的另一种类型的数据库。使用 Django REST 中的序列化程序可能会成功,这样您就可以强制执行您正在寻找的逻辑。

标签: django django-models database-design


【解决方案1】:

如果您使用的是 PostgreSQL,那么 Django 的 JSONField 可能会为您提供很好的服务 - reference

【讨论】:

  • 正如我所说,我正在使用 PostgreSQL 并且正在考虑 JSONField。但我不知道从我的结构转换为 JSON 的最佳方式是什么。特别是,我什至不知道我草拟的示例实现是否合理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-09-20
  • 1970-01-01
  • 2010-09-13
  • 2011-04-16
  • 2015-12-05
  • 1970-01-01
  • 2021-04-30
相关资源
最近更新 更多