【问题标题】:Django Database Design: Many-to-Many, Foreign Key, or neither?Django 数据库设计:多对多、外键或两者都不是?
【发布时间】:2012-02-11 13:12:33
【问题描述】:

一个菜鸟问题。我正在整理我的第一个数据库并遇到以下设计问题:我有一个定义一本书的类(例如它的标题)和一个定义页面的类(例如它的设计)。

课本的表格如下所示:

Title        | PAGE1        | PAGE2        | PAGE3
Book-One     | SAMPLE1-UUID | SAMPLE2-UUID | SAMPLE3-UUID
Book-Two     | SAMPLE4-UUID | SAMPLE5-UUID | SAMPLE6-UUID

班级页面的表格:

UUID         | FONT         | CONTENTS etc.
SAMPLE1-UUID | Times        | Example
SAMPLE2-UUID | Arial        | Example Two
SAMPLE3-UUID | Verdena      | Example Three

现在,由于每个页面都是独一无二的,并且不能在另一本书中重复使用,因此我不能对 Pages 使用多对多关系。我可以使用外键来链接这两个表,即将 Books 表的 SAMPLE1-UUID 与 Pages 表的 SAMPLE1-UUID 链接。这样做的好处是不会两次创建相同的条目。

但是,我不喜欢为我的页面设置固定数量的行。在上面的 Book 类示例中,我必须定义一组特定的页面,例如 PAGE1、PAGE2、PAGE3、PAGE4、... PAGE99。理想情况下,我只需要一个灵活的图书类页面列表,如下所示:

Name         | Pages
Book-One     | "SAMPLE1-UUID, SAMPLE2-UUID"
Book-Two     | "SAMPLE4-UUID, SAMPLE5-UUID, SAMPLE6-UUID"

Pages 是一个简单的 CharField,其内容是一个列表。但后来我遇到的问题是这两个表不再链接,我必须创建每个条目两次(即我必须在 pages 和 books 表中输入 SAMPLE1-UUID)。

还有其他方法来设计这个数据库吗?感谢您的任何建议!

【问题讨论】:

    标签: database django postgresql django-models


    【解决方案1】:

    我会这样做:

    class Book(models.Model):
        name=models.CharField(max_length=....)
    
    class Page(models.Model):
        book=models.ForeignKey(Book)
        number=models.PositiveIntegerField()
    

    我不明白您的书表示例:您想要 page1 的列和 page2 的其他列吗?这看起来很奇怪。

    【讨论】:

    • 谢谢 Guettli。是的,理想情况下,我希望有一个表格,列出所有页面及其布局属性——无论它们在哪本书中。例如如果我有两本书,每本书有 5 页,我的 pages 表将有 10 个条目。或者这也是糟糕的数据库设计?感谢您的帮助!
    【解决方案2】:

    您误解了外键的工作原理。这不是“固定数量的行”——事实上恰恰相反。

    正如 guettli 在他的回答中显示的那样,ForeignKey 字段是一对多的关系,在“多”方面定义。也就是说,Page 上定义的 ForeignKey 指向 Book,每个 Page 有一个 Book,但 Book 有多少个 Pages。

    因此,使用 Django ORM,如果您有一个 book 对象并且想要获取它的所有页面,您只需执行 my_book.page_set.all()

    【讨论】:

    • 谢谢!!是的,我把“多”的一面和“一”的一面搞混了。多么有帮助。现在更有意义了。所以换句话说,当我在我的数据库中输入一本书时,我并不关心它的页面。我现在唯一的问题:如果我在我的 django 管理数据库界面中查看一本书,我将看不到它有哪些页面。或者我可以通过 book.page_set.all() 添加这个吗?无论如何,非常感谢您的帮助!
    • 对于更改表单,您可以使用inline modeladmin 显示/编辑一本书的所有页面。
    【解决方案3】:

    我建议您不要将页面作为列:

    只有书籍信息的课程表看起来像这样:

    Title        | ISBN         
    Book-One     | XXXXXXXXXXXX 
    Book-Two     | YYYYYYYYYYYY 
    

    班级页面的表格:

    BOOKID       |PAGE_NUM | FONT         | CONTENTS
    1            |1        | Times        | Example
    1            |2        | Arial        | Example Two
    2            |1        | Verdena      | Example Three
    

    你的类设计应该是这样的:

    class Book(models.Model):
        title = models.CharField(max_length=100)
        isbn = models.CharField(max_length=100)
    
    class Page(models.Model):
        book = models.ForeignKey(Book)
        page_num = models.IntegerField()
        font = models.charField(max_length=100)
        content = models.TextField()
    

    您可以继续进行限制,例如一本书和 page_num 不会重复,但这可能是一个好的开始。

    【讨论】:

    • 谢谢凯尼。我唯一的问题是当我登录到我的 Django 管理界面时,我看不到每本书中有哪些页面。 Daniel Roseman 建议使用 my_book.page_set.all() 但我不确定在这种情况下如何翻译。我可以将它添加到我的 admin.py 中吗?无论管理界面如何,您如何获得 ID 为 1 的图书的所有页面列表?非常感谢您的帮助,非常感谢!
    • @n.evermind admin.StackedInline 是您正在寻找的。 Django documentation
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 2016-12-01
    • 2015-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多