我正在为 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',)
完全可以使用内联来实现 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
也许使用继承来代替 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)
在此变体中,您的产品将内联。
参考最后一个问题,对于多个子类型来说,最好的解决方案是什么。例如,具有子类型类 Book 和子类型类 CD 的产品类。按照此处所示的方式,您必须编辑产品、一般项目以及书籍的子类型项目和 CD 的子类型项目。因此,即使您只想添加一本书,您也会获得 CD 字段。如果您添加子类型,例如DVD,您会得到三个子类型字段组,而实际上您只需要一个子类型组,在提到的示例中:书籍。
您还可以尝试在 OneToOneField 上设置“parent_link=True”?
https://docs.djangoproject.com/en/dev/topics/db/models/#specifying-the-parent-link-field
使用 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)
是的,可以通过内联来实现一对一关系。
例如,如下所示,如果 "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, )