django admin中的通用多对多关系

时间:2022-10-04 12:06:18

I have few similar models in Django:

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

And model Topic, which is related to News and Article as ManyToMany.

和模型主题,与新闻和文章相关的ManyToMany。

I'd like to use Generic many-to-many relationships like in this case. But question is how to use default ManyToMany widget in django admin. Or another convenient analogue.

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

UPD: If I didn't use generics I'd write

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

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

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

And I'd get 2 identical tables that express these relationships. I wonder if I could use generics in order to have one intermediate table, because not only news and articles may have topic in my database. News and articles may be connected with 2 or more topics as well.

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

2 个解决方案

#1


7  

EDIT: Check this out http://charlesleifer.com/blog/connecting-anything-to-anything-with-django/

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

GenericForeignKey's are unfortunately not as well supported as ForeignKey's. There's an open (and accepted) ticket with patch for providing a widget for them: http://code.djangoproject.com/ticket/9976

遗憾的是,GenericForeignKey不像ForeignKey那样得到支持。有一个打开(并接受)的票据,附带补丁,为他们提供一个小部件:http://code.djangoproject.com/ticket/9976

What is provided out-of-the-box is managing objects with GenericForeignKey inline.

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

Assuming your generic relationship is achieved by

假设您的通用关系是通过

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')
    ...

and

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

If you want to edit the News of a Topic, you can define an inline admin for News:

如果要编辑主题新闻,可以为新闻定义内联管理员:

from django.contrib.contenttypes.generic import GenericTabularInline

class NewsInline(GenericTabularInline):
    model = News

and add it to the inlines of Topic admin:

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

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

That said, from the information given I can't see what's wrong with your ManyToMany relationship. It seems to express what you need.

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

Maybe you're defining the ManyToMany field in Topic instead of in News and Article? Define them in News and Article.

也许你在Topic中定义ManyToMany字段而不是在News和Article中?在新闻和文章中定义它们。

EDIT: Thanks for the clarification. Your model setup would be as per arie's post (i.e., the other way around) and you'd be editing inline. If you just want to select existing Topic's from inside a News/Article/etc. instance, I'm not aware of anything out-of-the-box for GenericRelation (which usually just serves as a reverse-lookup helper). You could

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

a) Override the admin form and add a ModelMultipleChoiceField with the queryset as per the GenericRelation

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

b) Override save() to adjust the relations.

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

Quite a lot of work. I would personally stick with multiple m2m tables and not cram everything into one. If you are afraid of the database doing multiple lookups when you ask for all News and Articles and etc. of one or more Topic's, then be aware that a generic solution will always have a similar setup to the requirements GenericForeignKey has, i.e. additional columns for model and id. That could lead to a lot more queries (e.g. against content_type for each result).

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

#2


2  

Shouldn't it work if you just turn Danny's example around and define the generic relation on the side of of the Topic-Model?

如果你只是转动Danny的例子并在主题模型的一侧定义泛型关系,它不应该工作吗?

See the example in django's docs: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#using-generic-relations-as-an-inline

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

Adapted to this question:

适应这个问题:

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

It probably makes sense to additionally define the reverse relationsship on each related model.

在每个相关模型上另外定义反向关系可能是有意义的。

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

And now you could create a TopicInline and attach Topics to news, articles, whatever ...

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

class TopicInline(generic.GenericTabularInline):
    model = Topic

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

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

#1


7  

EDIT: Check this out http://charlesleifer.com/blog/connecting-anything-to-anything-with-django/

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

GenericForeignKey's are unfortunately not as well supported as ForeignKey's. There's an open (and accepted) ticket with patch for providing a widget for them: http://code.djangoproject.com/ticket/9976

遗憾的是,GenericForeignKey不像ForeignKey那样得到支持。有一个打开(并接受)的票据,附带补丁,为他们提供一个小部件:http://code.djangoproject.com/ticket/9976

What is provided out-of-the-box is managing objects with GenericForeignKey inline.

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

Assuming your generic relationship is achieved by

假设您的通用关系是通过

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')
    ...

and

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

If you want to edit the News of a Topic, you can define an inline admin for News:

如果要编辑主题新闻,可以为新闻定义内联管理员:

from django.contrib.contenttypes.generic import GenericTabularInline

class NewsInline(GenericTabularInline):
    model = News

and add it to the inlines of Topic admin:

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

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

That said, from the information given I can't see what's wrong with your ManyToMany relationship. It seems to express what you need.

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

Maybe you're defining the ManyToMany field in Topic instead of in News and Article? Define them in News and Article.

也许你在Topic中定义ManyToMany字段而不是在News和Article中?在新闻和文章中定义它们。

EDIT: Thanks for the clarification. Your model setup would be as per arie's post (i.e., the other way around) and you'd be editing inline. If you just want to select existing Topic's from inside a News/Article/etc. instance, I'm not aware of anything out-of-the-box for GenericRelation (which usually just serves as a reverse-lookup helper). You could

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

a) Override the admin form and add a ModelMultipleChoiceField with the queryset as per the GenericRelation

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

b) Override save() to adjust the relations.

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

Quite a lot of work. I would personally stick with multiple m2m tables and not cram everything into one. If you are afraid of the database doing multiple lookups when you ask for all News and Articles and etc. of one or more Topic's, then be aware that a generic solution will always have a similar setup to the requirements GenericForeignKey has, i.e. additional columns for model and id. That could lead to a lot more queries (e.g. against content_type for each result).

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

#2


2  

Shouldn't it work if you just turn Danny's example around and define the generic relation on the side of of the Topic-Model?

如果你只是转动Danny的例子并在主题模型的一侧定义泛型关系,它不应该工作吗?

See the example in django's docs: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#using-generic-relations-as-an-inline

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

Adapted to this question:

适应这个问题:

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

It probably makes sense to additionally define the reverse relationsship on each related model.

在每个相关模型上另外定义反向关系可能是有意义的。

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

And now you could create a TopicInline and attach Topics to news, articles, whatever ...

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

class TopicInline(generic.GenericTabularInline):
    model = Topic

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

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