Django管理嵌套内联

gcuhipw9  于 2022-12-14  发布在  Go
关注(0)|答案(8)|浏览(215)

I need a nested django admin inline, which I can include the date field inlines in an other inline like below.
I have the models below:

class Person(models.Model):
     name = models.CharField(max_length=200)
     id_no = models.IntegerField()

class Certificate(models.Model):
     cerfificate_no = models.CharField(max_length=200)
     certificate_date = models.DateField(max_length=100)
     person = models.ForeignKey(Person)
     training = models.CharField(max_length=200)

class Training_Date(models.Model):
      date = models.DateField()
      certificate = models.ForeignKey(Certificate)

And, the admin below:

class CertificateInline(admin.StackedInline):
    model = Certificate

class PersonAdmin(admin.ModelAdmin):
     inlines = [CertificateInline,]
admin.site.register(Person,PersonAdmin)

But, I need to include the Training_Date model as inline which is part of Certificate admin inline.
Any idea?

q7solyqu

q7solyqu1#

There has been some movement in https://code.djangoproject.com/ticket/9025 recently, but I wouldn't hold my breath.
One common way around this is to link to an admin between first and second (or second and third) level by having both a ModelAdmin and an Inline for the same model:
Give Certificate a ModelAdmin with TrainingDate as an inline. Set show_change_link = True for CertificateInline so you can click on an inline to go to its ModelAdmin change form.
admin.py:

# Certificate change form has training dates as inline

class TrainingDateInline(admin.StackedInline):
    model = TrainingDate

class CertificateAdmin(admin.ModelAdmin):
    inlines = [TrainingDateInline,]
admin.site.register(Certificate ,CertificateAdmin)

# Person has Certificates inline but rather
# than nesting inlines (not possible), shows a link to
# its own ModelAdmin's change form, for accessing TrainingDates:

class CertificateLinkInline(admin.TabularInline):
    model = Certificate
    # Whichever fields you want: (I usually use only a couple
    # needed to identify the entry)
    fields = ('cerfificate_no', 'certificate_date')
    # Django 1.8 introduced this, no need to make your own link
    show_change_link = True

class PersonAdmin(admin.ModelAdmin):
    inlines = [CertificateLinkInline,]
admin.site.register(Person, PersonAdmin)
2skhul33

2skhul332#

更通用的解决方案

from django.utils.safestring import mark_safe
from django.urls import reverse

class EditLinkToInlineObject(object):
    def edit_link(self, instance):
        url = reverse('admin:%s_%s_change' % (
            instance._meta.app_label,  instance._meta.model_name),  args=[instance.pk] )
        if instance.pk:
            return mark_safe(u'<a href="{u}">edit</a>'.format(u=url))
        else:
            return ''

class MyModelInline(EditLinkToInlineObject, admin.TabularInline):
    model = MyModel
    readonly_fields = ('edit_link', )

class MySecondModelAdmin(admin.ModelAdmin):
    inlines = (MyModelInline, )

admin.site.register(MyModel)
admin.site.register(MySecondModel, MySecondModelAdmin)
zpqajqem

zpqajqem3#

pip install django-nested-inline

这个软件包应该能满足你的需要。

xu3bshqb

xu3bshqb4#

AFAIK,你不能在默认的Django管理中有第二级内联。
Django admin只是一个普通的Django应用程序,所以没有什么可以阻止你实现第二层嵌套表单,但恕我直言,这将是一种复杂的设计,也许这就是为什么没有提供它的原因。

x33g5p2x

x33g5p2x6#

A more up to date solution (february 2021) is to use the show_change_link config variable: https://docs.djangoproject.com/en/3.1/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin.show_change_link
This does exactly the same as the EditLinkToInlineObject proposed in solutions above, but is less code and is probably well tested by Django Developers
You would just have to define show_change_link=True in each one of your inlines
UPDATE (January 25th, 2022): Here's the updated link in the docs (Django 4.0): https://docs.djangoproject.com/en/4.0/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin.show_change_link

kxxlusnw

kxxlusnw7#

使用django-nested-admin,这是最好的内嵌包。
首先,安装**“django-nested-admin”**:

pip install django-nested-admin

然后,将**“nested_admin”添加到”www.example.com“中的“已安装应用程序”settings.py

# "settings.py"

INSTALLED_APPS = (
    # ...
    "nested_admin", # Here
)

然后,将**“路径('_nested_ad..."添加到”www.example.com“中的“网址模式”urls.py

# "urls.py"

from django.urls import include, path

urlpatterns = [
    # ...
    path('_nested_admin/', include('nested_admin.urls')), # Here
]

最后,在**”www.example.com“中使用“Training_DateInline()”和“CertificateInline()”类扩展“嵌套表格内联”,并使用“PersonAdmin()”类扩展“嵌套模型管理”admin.py,如下所示:

# "admin.py"

from .models import Training_Date, Certificate, Person
from nested_admin import NestedTabularInline, NestedModelAdmin

class Training_DateInline(NestedTabularInline):
    model = Training_Date

class CertificateInline(NestedTabularInline):
    model = Certificate
    inlines = [Training_DateInline]

@admin.register(Person)
class PersonAdmin(NestedModelAdmin):
    inlines = [CertificateInline]
ccrfmcuu

ccrfmcuu8#

我使用了@bigzbig提供的解决方案(谢谢)。
我还想回到第一个列表页面,一旦更改已保存,所以添加:

class MyModelInline(EditLinkToInlineObject, admin.TabularInline):
    model = MyModel
    readonly_fields = ('edit_link', )

    def response_post_save_change(self, request, obj):
        my_second_model_id = MyModel.objects.get(pk=obj.pk).my_second_model_id
        return redirect("/admin/mysite/mysecondmodel/%s/change/" % (my_second_model_id))

相关问题