【问题标题】:Generic many-to-many relationships in django admindjango admin中的通用多对多关系
【发布时间】:2011-08-07 16:34:42
【问题描述】:

我在 Django 中很少有类似的模型:

class Material(models.Model):
    title = models.CharField(max_length=255)
    class Meta:
        abstract = True

class News(Material):
    state = models.PositiveSmallIntegerField(choices=NEWS_STATE_CHOICES)

class Article(Material):
    genre = models.ForeignKey(Genre, verbose_name='genre')

以及模型Topic,与News和Article相关的ManyToMany。

我想使用像 case 这样的通用多对多关系。但问题是如何在 django admin 中使用默认的 ManyToMany 小部件。或者其他方便的类比。

UPD:如果我不使用泛型,我会写

class News(Material): 
    topic = models.ManyToMany(Topic) 

class Article(Material):
    topic = models.ManyToMany(Topic)

我会得到 2 个相同的表来表达这些关系。我想知道是否可以使用泛型来获得一个中间表,因为在我的数据库中不仅新闻和文章可能有主题。新闻和文章也可能与 2 个或更多主题相关。

【问题讨论】:

  • 不确定您链接到的问题是如何相关的。您是否想从与 Topic 的 ManyToMany 关系切换到为 Topic 提供 GenericForeignKey 以便您可以将其“附加”到任何对象?您希望在哪个方向拥有多选列表小部件?新闻选择其主题?如果它是通用关系,则主题的选择列表必须显示所有内容..

标签: django generics django-admin many-to-many


【解决方案1】:

编辑:查看http://charlesleifer.com/blog/connecting-anything-to-anything-with-django/

不幸的是,GenericForeignKey 的支持不如 ForeignKey。有一个开放(并已接受)的票证,其中包含为他们提供小部件的补丁:http://code.djangoproject.com/ticket/9976

开箱即用提供的是使用 GenericForeignKey 内联管理对象。

假设你的通用关系是通过

实现的
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from django.db import models

class News(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')
    ...

class Topic(models.Model):
    ...
    news = generic.GenericRelation('News')   # if separate app: 'newsapp.News'

如果您想编辑某个主题的新闻,您可以为新闻定义一个内联管理员:

from django.contrib.contenttypes.generic import GenericTabularInline

class NewsInline(GenericTabularInline):
    model = News

并将其添加到 Topic admin 的内联中:

class TopicAdmin(models.ModelAdmin):
    inlines = (NewsInline, )

也就是说,根据提供的信息,我看不出您的多对多关系有什么问题。它似乎表达了你的需要。

也许您是在主题中而不是在新闻和文章中定义 ManyToMany 字段?在新闻和文章中定义它们。

编辑:感谢您的澄清。您的模型设置将按照 arie 的帖子(即相反),并且您将在线编辑。如果您只想从新闻/文章/等中选择现有主题。例如,我不知道 GenericRelation 有任何开箱即用的东西(它通常只是用作反向查找助手)。你可以

a) 覆盖管理表单并根据 GenericRelation 添加带有查询集的 ModelMultipleChoiceField

b) 覆盖 save() 以调整关系。

相当多的工作。我个人会坚持使用多个 m2m 表,而不是将所有内容都塞进一张。如果您在询问一个或多个主题的所有新闻和文章等时担心数据库会进行多次查找,那么请注意,通用解决方案将始终具有与 GenericForeignKey 的要求类似的设置,即附加列型号和编号。这可能会导致更多查询(例如针对每个结果的 content_type)。

【讨论】:

  • 我有点困惑。尽管如此,在您的变体中,我打开主题条目并选择(或添加/删除)新闻和文章的新和平。这不是我想要的。我已经更新了问题。
  • 谢谢,但我几乎没有注意到您的编辑。我在 github 上看到过 django-generic-m2m 应用程序,但我不明白如何将它应用到 django admin。
  • 我正在尝试使用您的答案here,但我遇到了困难。想法?
【解决方案2】:

如果你只是把 Danny 的例子反过来并在Topic-Model 的一侧定义泛型关系,它不应该工作吗?

查看 django 文档中的示例:http://docs.djangoproject.com/en/dev/ref/contrib/admin/#using-generic-relations-as-an-inline

适应这个问题:

class Topic(models.Model):
    content_type = models.ForeignKey(ContentType)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey("content_type", "object_id")

在每个相关模型上额外定义reverse relationsship 可能是有意义的。

class News(models.Model):
    topics = generic.GenericRelation(Topic)

现在您可以创建一个TopicInline 并将主题附加到新闻、文章等...

class TopicInline(generic.GenericTabularInline):
    model = Topic

class ArticleAdmin(admin.ModelAdmin):
    inlines = [
        TopicInline,
    ]

class NewsAdmin(admin.ModelAdmin):
    inlines = [
        TopicInline,
    ]

【讨论】:

  • 但是如果主题已经创建,我可以使用 TabularInline 选择它吗?
猜你喜欢
  • 2012-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-17
  • 1970-01-01
  • 2018-10-29
  • 2016-04-18
  • 2015-02-15
相关资源
最近更新 更多