Django 管理后台:将一对一关系作为内联?
我正在为一个叫做Satchmo的应用程序搭建管理后台。Satchmo使用一对一的关系来扩展基本的Product
模型,我想在同一页面上编辑所有内容。
请问可以把一对一的关系放在内联编辑中吗?如果不行,最好的办法是什么,能在我的管理页面上添加几个字段,最后把它们保存到一对一的关系中?
举个例子:
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'>没有指向<class 'my_app.models.MyProduct'>的外键
难道唯一的解决办法就是使用自定义表单吗?
编辑:我刚刚尝试了以下代码直接添加字段……同样不成功:
class AlbumAdmin(admin.ModelAdmin):
fields = ('product__name',)
5 个回答
关于上一个问题,针对多个子类型,最好的解决方案是什么呢?比如说,有一个类叫做产品(Product),它有两个子类型,一个是书(Book),另一个是光盘(CD)。按照这里的方式,如果你想编辑一个产品,你就得同时修改通用的产品信息,还要修改书的子类型信息和光盘的子类型信息。所以即使你只想添加一本书,你也得处理光盘的字段。如果你再添加一个子类型,比如DVD,那你就会有三个子类型的字段组,但实际上你只想要一个子类型的字段组,在这个例子中就是书籍。
也许可以考虑使用继承,而不是一对一的关系。
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)
在这种情况下,你的产品会以嵌套的方式显示。
在一对一关系中使用内联是完全可以的。不过,定义这个关系的字段必须放在内联模型里,而不是父模型里——这和外键的情况是一样的。把它换过来就能正常工作了。
评论后补充: 你说父模型已经在管理员那里注册了,那就先取消注册,然后再重新注册。
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版本中,有些类型发生了变化,因为在ExtendedProductAdmin
中的inlines
现在应该作为列表添加,而不是元组,像这样:
class ExtendedProductAdmin(ProductAdmin):
inlines = ProductAdmin.inlines + [MyProductInline]
否则你会遇到这个错误:
inlines = ProductAdmin.inlines + (MyProductInline,)
TypeError: can only concatenate list (not "tuple") to list