【问题标题】:Django Database Design: ManyToManyField when using InlinesDjango 数据库设计:使用内联时的 ManyToManyField
【发布时间】:2012-02-12 07:22:05
【问题描述】:

我正在尝试设计我的第一个数据库,但有点卡住了。设计如下:你有一个可以有很多书的作者。每本书可以有很多页。每个页面可以有很多图片。每个页面都是唯一的 (ForeignKey)。图片可能不是唯一的(您可以在不同的页面/书籍中使用相同的图片,所以应该是ManyToMany)。 我的问题是使用Inlines 时无法将图片设为ManyToManyField

如果我将 ForeignKey 更改为 ManyToMany,则会收到异常“<class 'books.models.Picture'> has no ForeignKey to <class 'books.models.Page'>”。我看过herehere,但不知道如何在我的情况下应用它。

这就是我的 models.py 的样子:

class Author(models.Model):
    name = models.CharField(max_length=30)
    email = models.EmailField()

class Book(models.Model):
    author = models.ForeignKey(Author)
    title = models.CharField(max_length=50)

class Page(models.Model):
    book = models.ForeignKey(Book)
    contents = models.TextField(max_length=15999)

class Picture(models.Model):
    page = models.ForeignKey(Page) # ideally, this should be many-to-many
    picture_uuid = models.CharField(max_length=36)

在我的管理界面中,我想在作者页面上显示作者所写的所有书籍。另外,我想在书籍页面中拥有一本书的所有页面,依此类推。因此,我的 admin.py 看起来像这样:

class PictureAdmin(admin.ModelAdmin):
    list_display = ('id', 'picture_uuid')

class PictureInline(admin.TabularInline):
    model = Picture

class PageAdmin(admin.ModelAdmin):
    list_display = ('id', 'page_uuid')

    inlines = [
        PictureInline,
        ]

class PageInline(admin.TabularInline):
    model = Page

class BookAdmin(admin.ModelAdmin):
    list_display = ('id', 'title')

    inlines = [
        PageInline,
        ]

class BookInline(admin.TabularInline):
    model = Book

class AuthorAdmin(admin.ModelAdmin):
    list_display = ('id', 'name', 'email')

    inlines = [
        BookInline,
        ]

【问题讨论】:

    标签: database django postgresql django-models django-admin


    【解决方案1】:

    您不能将ManyToManyFields 直接用作内联。内联必须有一个外键返回到正在编辑的模型,当然实际的孩子没有。如果你想编辑 M2M 内联,你能做的最好的就是使用 through 表,所以你需要像这样改变你的 InlineModelAdmin

    class PictureInline(admin.TabularInline):
        model = Page.pictures.through
    

    这要求ManyToManyFieldPage 模型上:

    class Page(models.Model):
        ...
        pictures = models.ManyToManyField(Picture)
    

    【讨论】:

    • 工作得很好,除了我现在在一个页面上有两个部分可以选择图片。一个外键下拉菜单选择一张图片,一个普通的多对多菜单选择一张图片。我怎样才能摆脱第二个?
    • 只需将实际字段添加到您的ModelAdminexcludes
    • 一般情况下,不,您不会将相同的关系添加到同一个模型两次。我以前从来没有想过这样做,因为我从来没有需要。 Django 为 M2M 关系创建的默认中间表可能会对两个外键强制执行唯一的共同约束。您可以通过创建自己的 through 模型来解决这个问题。
    • 您必须将raw_id_fields 放在您的inline 类中。 InlineModelAdmins(在大多数情况下)在功能上与常规 ModelAdmins 相同。字段集、排除项等内容在 InlineModelAdmin 上定义,就像在 ModelAdmin 上一样。
    • 这是因为through 模型上的字段不是“图片”而是picture
    【解决方案2】:

    根据https://docs.djangoproject.com/en/dev/ref/contrib/admin/#working-with-many-to-many-models 中的文档,您必须在您的内联中定义model 属性

    【讨论】:

    • 嗯...他做到了。而且,无论如何,这不是问题。
    • @ChrisPratt 如果您看到我指向的链接,您会注意到我的答案与您的几乎相同,当我说定义模型时,我的意思是 model = Page.pictures.through跨度>
    • 那为什么要发布一个仅仅暗示与我的答案相同的答案?
    • 当我回答这个问题时,我的页面没有刷新:)
    猜你喜欢
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 2019-09-06
    • 1970-01-01
    • 1970-01-01
    • 2013-01-03
    • 2018-01-31
    • 2019-03-24
    相关资源
    最近更新 更多