简体   繁体   English

Django Admin:OneToOne 关系作为内联?

[英]Django Admin: OneToOne Relation as an Inline?

I'm putting together the admin for a satchmo application.我正在为一个 satchmo 应用程序组合管理员。 Satchmo uses OneToOne relations to extend the base Product model, and I'd like to edit it all on one page. Satchmo 使用 OneToOne 关系来扩展基本Product模型,我想在一页上对其进行编辑。

Is it possible to have a OneToOne relation as an Inline?是否可以将 OneToOne 关系作为内联? If not, what is the best way to add a few fields to a given page of my admin that will eventually be saved into the OneToOne relation?如果没有,将一些字段添加到我的管理员的给定页面最终将保存到 OneToOne 关系中的最佳方法是什么?

for example:例如:

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

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

I tried this for my admin but it does not work, and seems to expect a Foreign Key:我为我的管理员尝试了这个,但它不起作用,并且似乎需要一个外键:

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

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

admin.site.register(MyProduct, MyProductAdmin)

Which throws this error: <class 'satchmo.product.models.Product'> has no ForeignKey to <class 'my_app.models.MyProduct'>引发此错误: <class 'satchmo.product.models.Product'> has no ForeignKey to <class 'my_app.models.MyProduct'>

Is the only way to do this a Custom Form ?这样做的唯一方法是自定义表单吗?

edit: Just tried the following code to add the fields directly... also does not work:编辑:刚刚尝试以下代码直接添加字段......也不起作用:

class AlbumAdmin(admin.ModelAdmin):
    fields = ('product__name',)

It's perfectly possible to use an inline for a OneToOne relationship.完全可以将内联用于 OneToOne 关系。 However, the actual field defining the relationship has to be on the inline model, not the parent one - in just the same way as for a ForeignKey.但是,定义关系的实际字段必须位于内联模型上,而不是父模型上 - 与 ForeignKey 的方式相同。 Switch it over and it will work.切换它,它会工作。

Edit after comment : you say the parent model is already registered with the admin: then unregister it and re-register.评论后编辑:您说父模型已经向管理员注册:然后取消注册并重新注册。

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)

Update 2020 (Django 3.1.1) 2020 年更新(Django 3.1.1)

This method is still working but some types has changed in new Django version since inlines in ExtendedProductAdmin should now be added as list and not tuple, like this:此方法仍在工作,但新Django版本中的某些类型已更改,因为现在应该将ExtendedProductAdmin中的内inlines添加为列表而不是元组,如下所示:

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

Or you will get this error:或者你会得到这个错误:

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

Maybe use inheritance instead OneToOne relationship也许使用继承而不是 OneToOne 关系

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

class MyProduct(Product):
    .....

Or use proxy classes或者使用代理类

class ProductProxy(Product)
    class Meta:
        proxy = True

in admin.py在 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)

In this variant your product will be in inline.在此变体中,您的产品将内联。

Referring to the last question, what would be the best solution for multiple sub-types.关于最后一个问题,对于多个子类型,最佳解决方案是什么。 Eg class Product with sub-type class Book and sub-type class CD.例如,具有子类型类 Book 和子类型类 CD 的类 Product。 The way shown here you would have to edit a product the general items plus the sub-type items for book AND the sub-type items for CD.此处显示的方式您必须编辑产品的一般项目加上书籍的子类型项目和 CD 的子类型项目。 So even if you only want to add a book you also get the fields for CD.因此,即使您只想添加一本书,您也可以获得 CD 字段。 If you add a sub-type eg DVD, you get three sub-type field groups, while you actually only want one sub-type group, in the mentioned example: books.如果您添加一个子类型,例如 DVD,您将获得三个子类型字段组,而实际上您只需要一个子类型组,在上述示例中:书籍。

You can also try setting 'parent_link=True' on your OneToOneField?您也可以尝试在 OneToOneField 上设置“parent_link=True”?

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

Jun, 2022 Update: 2022 年 6 月更新:

Yes, it's possible to have inline for one-to-one relation .是的,一对一关系可以内联

For example, as shown below, if "MyProduct" class has "models.OneToOneField()" referring to "Product" class which means "MyProduct" class has the ForeignKey referring to "Product" class :例如,如下所示,如果“MyProduct”类“models.OneToOneField()”引用“Product”类,这意味着“MyProduct”类ForeignKey引用“Product”类

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

Then, you can inline "MyProduct" class under "Product" class as shown below:然后,您可以在“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, )

Oppositely, as shown below, if "Product" class has "models.OneToOneField()" referring to "MyProduct" class which means "Product" class has the ForeignKey referring to "MyProduct" class :相反,如下图所示,如果“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
    )

Then, you can inline "Product" class under "MyProduct" class as shown below:然后,您可以在“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, )

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM