django管理员中的通用多对多关系 [英] Generic many-to-many relationships in django admin

查看:1718
本文介绍了django管理员中的通用多对多关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Django中有几个类似的模型:

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

class新闻(素材):
state = models.PositiveSmallIntegerField(choices = NEWS_STATE_CHOICES)

类文章(材料):
genre = models.ForeignKey(类型,verbose_name ='类型')

主题相关的新闻和文章为ManyToMany。



我想使用通用的多对多关系,如案例。但问题是如何在django管理员中使用默认的ManyToMany小部件。或另一个方便的模拟。



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

  class News(Material):
topic = models.ManyToMany(主题)

类文章(材质):
主题= models.ManyToMany(主题)

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

解决方案

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



GenericForeignKey不幸不如ForeignKey的支持。有一个开放(并且被接受)的机票与补丁为他们提供一个小部件: http://code.djangoproject.com/ticket/9976



现有的提供的是使用GenericForeignKey内联管理对象的内容。



假设您的通用关系是通过

 从django.contrib.contenttypes导入通用
从django.contrib.contenttypes .models import来自django.db的ContentType
import models

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

 类主题(models.Model):
...
news = generic.GenericRelation('News')#如果单独的app:'newsapp.News'

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

  from django.contrib.contenttypes .generic import GenericTabularInline 

class NewsInline(GenericTabularInline):
model =新闻

并将其添加到主题管理的内容:

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

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



也许你在主题中定义了ManyToMany字段,而不是在新闻和文章中?在新闻和文章中定义他们。



编辑:感谢您的澄清。您的模型设置将按照arie的职位(即相反的方式),您将在线编辑。如果您只想从News / Article / etc里面选择现有的主题。实例,我并没有意识到GenericRelation的任何开箱即用(通常只是作为反向查找帮助器)。您可以



a)覆盖管理表单,并按照GenericRelation



b向查询器添加一个ModelMultipleChoiceField )覆盖save()来调整关系。



相当多的工作。我会亲自粘贴多个m2m表,而不是将所有内容都包装成一个。如果您在询问一个或多个主题的所有新闻和文章等时害怕数据库执行多个查找,那么请注意,通用解决方案将始终具有与GenericForeignKey所需的相似设置,即附加列模型和id。这可能会导致更多的查询(例如针对每个结果的content_type)。


I have few similar models in 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.

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.

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

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.

解决方案

EDIT: Check this out 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

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

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.

Maybe you're defining the ManyToMany field in Topic instead of in News and Article? Define them in News and 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

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

b) Override save() to adjust the relations.

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

这篇关于django管理员中的通用多对多关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆