60

我需要一个嵌套的 django admin 内联,我可以将日期字段内联包含在另一个内联中,如下所示。

我有以下模型:

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)

和下面的管理员:

class CertificateInline(admin.StackedInline):
    model = Certificate

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

但我需要将 Training_Date 模型作为内联包含在内,这是证书管理内联的一部分。

任何想法 ?

4

7 回答 7

41

最近https://code.djangoproject.com/ticket/9025有一些动静,但我不会屏住呼吸。

ModelAdmin解决此问题的一种常见方法是通过为同一模型同时具有 a 和 Inline 来链接到第一和第二(或第二和第三)级别之间的管理员:

Certificate一个ModelAdminwithTrainingDate作为内联。提供CertificateInline一个附加字段“详细信息”,该字段是其ModelAdmin更改表单的链接。

模型.py:

from django.core import urlresolvers

class Certificate(models.Model):
    
    # ...
    
    def changeform_link(self):
        if self.id:
            # Replace "myapp" with the name of the app containing
            # your Certificate model:
            changeform_url = urlresolvers.reverse(
                'admin:myapp_certificate_change', args=(self.id,)
            )
            return u'<a href="%s" target="_blank">Details</a>' % changeform_url
        return u''
    changeform_link.allow_tags = True
    changeform_link.short_description = ''   # omit column header

管理员.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', 'changeform_link')
    readonly_fields = ('changeform_link', )

class PersonAdmin(admin.ModelAdmin):
    inlines = [CertificateLinkInline,]
admin.site.register(Person, PersonAdmin)
于 2013-01-14T23:29:19.627 回答
29

更通用的解决方案

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)
于 2014-03-01T11:47:45.547 回答
19
pip install django-nested-inline

这个包应该做你需要的。

于 2014-10-26T16:46:19.580 回答
17

AFAIK,您不能在默认的 Django 管理员中拥有第二级内联。

Django admin 只是一个普通的 Django 应用程序,所以没有什么能阻止您实现第二级嵌套表单,但恕我直言,这将是一种复杂的设计来实现。也许这就是为什么没有规定的原因。

于 2013-01-13T22:18:35.300 回答
5

嵌套内联在: https ://github.com/BertrandBordage/django-super-inlines/

pip install django-super-inlines
于 2015-05-15T00:44:50.667 回答
4

更新的解决方案(2021 年 2 月)是使用show_change_link配置变量:https ://docs.djangoproject.com/en/3.1/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin.show_change_link

这与上述解决方案中提出的 EditLinkToInlineObject 完全相同,但代码更少,并且可能已经过 Django 开发人员的良好测试

您只需要show_change_link=True在每个内联中定义

更新(2022 年 1 月 25 日):这是文档中的更新链接(Django 4.0):https ://docs.djangoproject.com/en/4.0/ref/contrib/admin/#django.contrib.admin.InlineModelAdmin.show_change_link

于 2021-02-07T23:16:26.747 回答
2

我使用了@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))
于 2018-01-27T14:47:49.520 回答