django admin中的通用多对多关系

时间:2011-04-18 08:05:31

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

我在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')

模型主题,与News和Article作为ManyToMany相关。

我想使用像case这样的通用多对多关系。但问题是如何在django admin中使用默认的ManyToMany小部件。或者另一种方便的模拟。

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

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

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

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

2 个答案:

答案 0 :(得分:7)

编辑:检查一下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

并将其添加到主题管理员的内联中:

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

那就是说,根据给出的信息,我看不出你的ManyToMany关系有什么问题。它似乎表达了你的需要。

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

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

a)覆盖管理表单并根据GenericRelation

添加带有查询集的ModelMultipleChoiceField

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

相当多的工作。我个人会坚持使用多个m2m表,而不是把所有东西都塞进去。如果您害怕数据库在请求一个或多个主题的所有新闻和文章等时进行多次查找,那么请注意,通用解决方案将始终具有与GenericForeignKey具有的要求类似的设置,即模特和身份证。这可能会导致更多查询(例如,针对每个结果的content_type)。

答案 1 :(得分:2)

如果你只是转动Danny的例子来定义Topic - 模型旁边的泛型关系吗?

请参阅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,
    ]