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

我正在为 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',)
45087 次浏览

在 OneToOne 关系中使用内联是完全可能的。但是,定义关系的实际字段必须位于内联模型上,而不是父模型上——这与 ForeignKey 的方式相同。把它换过来,它就会工作。

在注释后编辑 : 您说父模型已经在管理员那里注册了: 然后取消注册并重新注册。

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)

这个方法仍然可以工作,但是在新的 姜戈版本中,一些类型发生了变化,因为 ExtendedProductAdmin中的 inlines现在应该以 list 而不是 tuple 的形式添加,如下所示:

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

否则你会得到这个错误:

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

关于最后一个问题,对于多个子类型,什么是最好的解决方案。例如类别产品与子类别书籍和子类别光盘。这里显示的方法,你必须编辑一个产品的一般项目加上子类型的项目为书和子类型的项目为 CD。因此,即使您只想添加一本书,您也可以获得 CD 的字段。如果你添加一个子类型,例如 DVD,你会得到三个子类型字段组,而实际上你只需要一个子类型组,在上面的例子中: books。

也许可以用继承来代替 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)

在此变体中,您的产品将处于内联状态。

你也可以尝试在你的 OneToOneField 上设置‘ rent _ link = True’?

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

2022年6月更新:

是的,有可能 内嵌式一对一的关系

例如,如下所示,如果 “ MyProduct”类“模特. OneToOneField ()”“产品”类,这意味着 “ MyProduct”类外国钥匙“产品”类:

# "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
)

然后,您可以在 “产品”类下嵌入 “ 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, )

相反,如下所示,如果 “产品”类“模特. OneToOneField ()”“ MyProduct”类,这意味着 “产品”类外国钥匙“ 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”类下嵌入 “产品”类,如下所示:

# "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, )