Django数据库设计:使用Inlines时的ManyToManyField

3
我正在尝试设计我的第一个数据库,但遇到了一些困难。设计如下:您有一个作者可以拥有多本书。每本书可以有许多页面。每个页面可以有许多图片。每个页面都是唯一的(ForeignKey)。图片可能不是唯一的(您可以在不同的页面/书中使用相同的图片,因此这应该是ManyToMany)。我的问题是,当使用Inlines时,我无法将图片设置为ManyToManyField 如果我将ForeignKey更改为ManyToMany,我会收到异常“<class 'books.models.Picture'> has no ForeignKey to <class 'books.models.Page'>”。我看了一下这里这里,但不知道如何在我的情况下应用它。
这是我的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,
        ]
2个回答

3

直接使用ManyToManyFields不能作为内联。 内联必须具有与正在编辑的模型相反的外键,并且当然实际子级没有此类外键。 如果您想要编辑M2M inline,则最好的方法是使用through表,因此您需要修改InlineModelAdmin的方式:

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

这要求ManyToManyField必须在Page模型上:

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

运作良好,除了现在我有两个页面部分可以选择图片。一个外键下拉菜单用于选择图片,另一个普通的多对多菜单也能选择图片。我如何消除第二个菜单? - n.evermind
1
只需将实际字段添加到您的ModelAdminexcludes中。 - Chris Pratt
1
一般来说,不要将相同的关系添加到相同的模型两次。我以前从未考虑过这样做,因为我从未有过这样的需求。Django为M2M关系创建的默认中介表可能会对两个外键强制执行唯一在一起的约束条件。您可以通过创建自己的 “through” 模型来解决这个问题。 - Chris Pratt
1
你必须在inline类上放置raw_id_fieldsInlineModelAdmin(大部分)与常规的ModelAdmin具有完全相同的功能。例如,像字段集、排除等等这些东西都可以在InlineModelAdmin上定义,就像在ModelAdmin上一样。 - Chris Pratt
1
这是因为through模型上的字段不是"pictures",而是picture - Chris Pratt
显示剩余7条评论

0

2
嗯...他确实这样做了。但是,那不是问题的关键。 - Chris Pratt
@ChrisPratt,如果你看到我指向的链接,你会注意到我的答案基本上和你的一样。当我说定义一个模型时,我是指模型=Page.pictures.through。 - armonge
2
那么为什么要发布一个回答,仅仅建议与我的答案相同的事情呢? - Chris Pratt
当我回答这个问题时,我的页面还没有刷新 :) - armonge

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接