Django 管理员:一对一关系作为内联?

问题描述 投票:0回答:6

我正在为 satchmo 应用程序整理管理员。 Satchmo 使用 OneToOne 关系来扩展基本

Product
模型,我想在一页上编辑所有内容。

是否可以将 OneToOne 关系作为内联关系?如果没有,向我的管理员的给定页面添加一些字段(最终将保存到 OneToOne 关系中)的最佳方法是什么?

例如:

class Product(models.Model):
    name = models.CharField(max_length=100)
    ...

class MyProduct(models.Model):
    product = models.OneToOne(Product)
    ...

我为我的管理员尝试过此操作,但它不起作用,并且似乎需要外键:

class ProductInline(admin.StackedInline):
    model = Product
    fields = ('name',)

class MyProductAdmin(admin.ModelAdmin):
    inlines = (AlbumProductInline,)

admin.site.register(MyProduct, MyProductAdmin)

这会引发此错误:

<class 'satchmo.product.models.Product'> has no ForeignKey to <class 'my_app.models.MyProduct'>

唯一的方法是使用自定义表单吗?

编辑:刚刚尝试了以下代码直接添加字段...也不起作用:

class AlbumAdmin(admin.ModelAdmin):
    fields = ('product__name',)
python python-3.x django django-admin one-to-one
6个回答
89
投票

完全可以使用内联来实现 OneToOne 关系。然而,定义关系的实际字段必须位于内联模型上,而不是父模型上——就像外键一样。切换一下就可以了。

评论后编辑:你说父模型已经向管理员注册:然后取消注册并重新注册。

from original.satchmo.admin import ProductAdmin

class MyProductInline(admin.StackedInline):
    model = MyProduct

class ExtendedProductAdmin(ProductAdmin):
    inlines = ProductAdmin.inlines + (MyProductInline,)

admin.site.unregister(Product)
admin.site.register(Product, ExtendedProductAdmin)

2020 年更新(Django 3.1.1)

此方法仍然有效,但某些类型在新的 Django 版本中发生了变化,因为

inlines
中的
ExtendedProductAdmin
现在应该添加为列表而不是元组,如下所示:

class ExtendedProductAdmin(ProductAdmin):
    inlines = ProductAdmin.inlines + [MyProductInline]

否则你会得到这个错误:

    inlines = ProductAdmin.inlines + (MyProductInline,)
TypeError: can only concatenate list (not "tuple") to list

8
投票

也许使用继承来代替 OneToOne 关系

class Product(models.Model):
    name = models.CharField(max_length=100)
    ...

class MyProduct(Product):
    .....

或者使用代理类

class ProductProxy(Product)
    class Meta:
        proxy = True

在admin.py中

class MyProductInlines(admin.StackedInline):
    model = MyProduct

class MyProductAdmin(admin.ModelAdmin):
    inlines = [MyProductInlines]

    def queryset(self, request):
        qs = super(MyProductAdmin, self).queryset(request)
        qs = qs.exclude(relatedNameForYourProduct__isnone=True)
        return qs

admin.site.register(ProductProxy, MyProductAdmin)

在此变体中,您的产品将内联。


5
投票

参考最后一个问题,对于多个子类型来说,最好的解决方案是什么。例如,具有子类型类 Book 和子类型类 CD 的产品类。按照此处所示的方式,您必须编辑产品、一般项目以及书籍的子类型项目和 CD 的子类型项目。因此,即使您只想添加一本书,您也会获得 CD 字段。如果您添加子类型,例如DVD,您会得到三个子类型字段组,而实际上您只需要一个子类型组,在提到的示例中:书籍。


2
投票

您还可以尝试在 OneToOneField 上设置“parent_link=True”?

https://docs.djangoproject.com/en/dev/topics/db/models/#specifying-the-parent-link-field


0
投票

使用 django-reverse-admin is 也可以在父(而不是内联)模型中定义关系。内联模型也不需要有一个单独的 Admin 类,我发现它对于简单的情况来说更干净:

from django_reverse_admin import ReverseModelAdmin

class PersonAdmin(ReverseModelAdmin):
    inline_type = 'tabular'
    inline_reverse = [
        'business_addr',
        ('home_addr', {'fields': ['street', 'city', 'state', 'zipcode']}),
    ]

admin.site.register(Person, PersonAdmin)

-1
投票

2022 年 6 月更新:

是的,可以通过内联来实现一对一关系

例如,如下所示,如果 "MyProduct" 类"models.OneToOneField()" 引用 "Product" 类,则意味着 "MyProduct" 类 具有 ForeignKey 引用 "产品”类

# "models.py"

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=100)

class MyProduct(models.Model):
    name = models.CharField(max_length=100)
    product = models.OneToOneField( # Here
        Product, 
        on_delete=models.CASCADE,
        primary_key=True
    )

然后,您可以在“Product”类下内联“MyProduct”类,如下所示:

# "admin.py"

from django.contrib import admin
from .models import Product, MyProduct

class MyProductInline(admin.TabularInline):
    model = MyProduct

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    inlines = (MyProductInline, )

相反,如下所示,如果 "Product" 类"models.OneToOneField()" 引用 "MyProduct" 类,这意味着 "Product" 类 具有 ForeignKey 引用 "MyProduct “类

# "models.py"

from django.db import models

class MyProduct(models.Model):
    name = models.CharField(max_length=100)

class Product(models.Model):
    name = models.CharField(max_length=100)
    my_product = models.OneToOneField( # Here
        MyProduct, 
        on_delete=models.CASCADE,
        primary_key=True
    )

然后,您可以在“MyProduct”类下内联“Product”类,如下所示:

# "admin.py"

from django.contrib import admin
from .models import Product, MyProduct

class ProductInline(admin.TabularInline):
    model = Product

@admin.register(MyProduct)
class MyProductAdmin(admin.ModelAdmin):
    inlines = (ProductInline, )
© www.soinside.com 2019 - 2024. All rights reserved.