2013-01-13 148 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))