在Django管理员中,添加一个通用关系的内联

时间:2017-10-24 21:38:16

标签: python django

以下是我的简化模型:

from django.contrib.contenttypes.fields import (
    GenericForeignKey, GenericRelation)
from django.db import models
from django.utils.translation import ugettext_lazy as _


class Thing(models.Model):
    '''
    Our 'Thing' class
    with a link (generic relationship) to an abstract config
    '''

    name = models.CharField(
        max_length=128, blank=True,
        verbose_name=_(u'Name of my thing'))

    # Link to our configs
    config_content_type = models.ForeignKey(
        ContentType,
        null=True,
        blank=True)
    config_object_id = models.PositiveIntegerField(
        null=True,
        blank=True)
    config_object = GenericForeignKey(
        'config_content_type',
        'config_object_id')


class Config(models.Model):
    '''
    Base class for custom Configs
    '''
    class Meta:
        abstract = True

    name = models.CharField(
        max_length=128, blank=True,
        verbose_name=_(u'Config Name'))

    thing = GenericRelation(
        Thing,
        related_query_name='config')


class FirstConfig(Config):
    pass


class SecondConfig(Config):
    pass

以下是管理员:

from django.contrib import admin
from .models import FirstConfig, SecondConfig, Thing


class FirstConfigInline(admin.StackedInline):
    model = FirstConfig


class SecondConfigInline(admin.StackedInline):
    model = SecondConfig


class ThingAdmin(admin.ModelAdmin):
    model = Thing

    def get_inline_instances(self, request, obj=None):
    '''
    Returns our Thing Config inline
    '''
        if obj is not None:
            m_name = obj.config_object._meta.model_name
            if m_name == "firstconfig":
                return [FirstConfigInline(self.model, self.admin_site), ]
            elif m_name == "secondconfig":
                return [SecondConfigInline(self.model, self.admin_site), ]
        return []


admin.site.register(Thing, ThingAdmin)

到目前为止,我已经将FirstConfig对象链接在一起的Thing对象。 代码被简化:在一个不相关的部分,我设法在Thing创建时创建我的抽象Config并设置正确的content_type / object_id。

现在我想在我的ThingAdmin中看到这个FirstConfig实例作为内联(FirstConfigInline)。

我尝试使用django.contrib.contenttypes.admin.GenericStackedInline,但它不适用于我当前的模型设置。
我尝试使用我的FirstConfigInline的fk_name参数 另外,正如你所看到的,我试图用“''我的配置模型上的GenericRelation属性,没有成功..

有关如何正确设置管理员的任何想法吗?

2 个答案:

答案 0 :(得分:0)

根据Django Docs,您必须定义ct_fk_field和ct_field(如果它们已从默认值更改)。因此将ct_field设置为config_content_type可能就足够了。

希望它有效!

编辑:必须在内联中声明这些值:

class SecondConfigInline(admin.StackedInline):
    model = SecondConfig
    ct_fk_field = "config_object_id"
    ct_field = "config_content_type"

EDIT2:

我刚刚在我的假设中意识到错误。通常,您应该在Inline模型中声明Foreignkey。根据您的其余代码,您可以删除Thing上的通用外键+ Config上的genericRelation,并在Config-Basemodel上声明一个正常的外键。

答案 1 :(得分:0)

这个问题很旧,但是我还是尝试一下。

我认为解决方案取决于您打算在ThingConfig子类之间创建什么样的关系。

多对一/一对多

当前设置的方式看起来像多对一关系:每个Thing指向一个单独的Config子类,许多Thing可以指向相同的Config子类。由于具有通用关系,每个Thing都可以指向不同的模型(不一定要Config的子类,除非您做一些额外的工作)。

在这种情况下,我想将内联放置在Config的管理员身上会更有意义。也就是说,为GenericStackedInline(具有Thing)创建一个GenericForeignkey,并将内联添加到ConfigAdmin,然后可以将其用于所有{{1} }子类。另请参见下面的示例。然后,通用内联会自动设置正确的Configcontent_type

多对多

另一方面,如果您要在object_id和每个Thing子类之间寻找多对多关系,则可以将Config移到单独的多对多表(将其称为GenericForeignkey)。

一些代码可以说一千多个单词,所以让我们按如下方式拆分ThingConfigRelation类:

Thing

现在可以在class Thing(models.Model): name = models.CharField(max_length=128) class ThingConfigRelation(models.Model): thing = models.ForeignKey(to=Thing, on_delete=models.CASCADE) content_type = models.ForeignKey(ContentType, null=True, blank=True, on_delete=models.CASCADE) object_id = models.PositiveIntegerField(null=True, blank=True) config_object = GenericForeignKey(ct_field='content_type', fk_field='object_id') 中添加内联了。以下是适用于关系双方的管理员的准系统示例:

ThingAdmin

请注意,我们在关系的from django.contrib import admin from django.contrib.contenttypes.admin import GenericStackedInline from .models import Thing, FirstConfig, SecondConfig, ThingConfigRelation class ConventionalTCRInline(admin.StackedInline): model = ThingConfigRelation extra = 0 class GenericTCRInline(GenericStackedInline): model = ThingConfigRelation extra = 0 class ThingAdmin(admin.ModelAdmin): inlines = [ConventionalTCRInline] class ConfigAdmin(admin.ModelAdmin): inlines = [GenericTCRInline] admin.site.register(Thing, ThingAdmin) admin.site.register(FirstConfig, ConfigAdmin) admin.site.register(SecondConfig, ConfigAdmin) 侧(即ForeignKey)中使用常规内联,而在ThingAdmin侧({ {1}}。

一个棘手的事情是过滤GenericForeignKey上的ConfigAdmincontent_type字段。

...完全不同:

另一种选择可能是完全摆脱object_id并使用某种具有普通旧ThingAdmin的单表继承实现,有点像this