2013-01-13 149 views
28

我需要一个嵌套的Django管理内联, ,我可以在其他内联如下所示内嵌日期字段内联。Django管理嵌套内联

我有以下型号:

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模型直列这是证书管理内嵌的一部分。

有什么想法?

回答

9

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

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

+0

我面临着类似的情况。我想我会重写内联模板并添加一些链接到第二级。 – Damon

31

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

围绕这一点的一种常见方式是通过同时具有的ModelAdmin和内联该同样的模型链接到第一和第二(或第二和第三)电平之间的管理员:

给证明书的ModelAdmin与TrainingDate如内联。为CertificateInline添加一个额外的字段“Details”,该字段是指向其ModelAdmin更改表单的链接。

models.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 

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', 'changeform_link') 
    readonly_fields = ('changeform_link',) 

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

这是一个不错的解决方案。我想指出,你可以把'changeform_link'放在'CertificateLinkInline'中。这可能是一个更好的地方,因为它是特定于django-admin的。请注意,当你这样做时,你应该使用'instance.id'而不是'self.id'来获取模型的实例。见https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields – rednaw

+0

如果changeform_link方法产生一个异常,那么django会吃掉并继续,离开该域空白。我从来没有能够找到django在什么地方放置这个回溯,或者如果它对它做任何事情。我建议在尝试/包装它,除非确保异常记录在某处。为了简化,创建一个装饰器处理所有这些可能是有用的。 –

9

更通用的解决方案

from django.utils.safestring import mark_safe 
from django.core.urlresolvers 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) 
+0

简单而灵活。 +1 – yekta

8
pip install django-nested-inline 

这个包应该做你所需要的。在提供

+0

** django-nested-inline **在最新的django发行版中尚未支持(尚未?)。 但你可以考虑使用https://github.com/theatlantic/django-nested-admin,这几乎是一样的。 – vmonteco

+0

@vmonteco你能给我一个链接到文档,在那里描述如何使用它没有包? –

+1

@OleksandrDashkov http://django-nested-admin.readthedocs.io/en/latest/,位于github页面的顶部。但可能仍然必须安装该软件包。 – vmonteco

0

我使用@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))