2013-01-13 27 views
28

Potrzebuję zagnieżdżonego administratora django, , który może zawierać inline pola daty w innym wierszu, jak poniżej.Django Admin zagnieżdżony inline

Mam modeli poniżej:

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) 

i poniżej admin:

class CertificateInline(admin.StackedInline): 
    model = Certificate 

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

ale muszę to model Training_Date jako inline, który jest częścią certyfikatu administratora inline.

Każdy pomysł?

Odpowiedz

9

AFAIK, nie można mieć drugiego poziomu inline w domyślnym administratorze Django.

Administrator Django to zwyczajna aplikacja Django, więc nic nie stoi na przeszkodzie, aby wdrożyć drugi poziom zagnieżdżonych formularzy, ale IMHO byłby to rodzaj skomplikowanego projektu do wdrożenia. Być może dlatego nie ma na to przepisu.

+0

mam do czynienia z podobnym scenariuszem. Myślę, że zamierzam po prostu zastąpić wbudowany szablon i dodać kilka linków do drugiego poziomu. – Damon

31

Ostatnio nastąpił pewien ruch w https://code.djangoproject.com/ticket/9025, ale nie wstrzymałbym się.

Jeden wspólny sposób wokół to jest link do administratora pomiędzy pierwszą i drugą (lub drugi i trzeci) poziom, zarówno o ModelAdmin i inline z tego samego modelu:

Give Świadectwo ModelAdmin z TrainingDate jako inline. Daj CertificateInline dodatkowe pole "Szczegóły", które jest linkiem do jego formularza zmiany 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

To jest dobre rozwiązanie. Chcę zaznaczyć, że możesz umieścić 'changeform_link' w' CertificateLinkInline'. To może być lepsze miejsce, ponieważ jest specyficzne dla django-admin. Zauważ, że kiedy to zrobisz, powinieneś użyć 'instance.id' zamiast' self.id' aby dostać się do instancji modelu. Zobacz https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.readonly_fields – rednaw

+0

Jeśli metoda changeform_link wygeneruje wyjątek, django go zje i kontynuuje, opuszczając pole pusty.Nigdy nie byłem w stanie znaleźć miejsca, w którym django umieszcza traceback lub jeśli w ogóle coś z nim robi. Proponuję zawinąć to w próbie/wyjątkiem, by upewnić się, że wyjątek zostanie gdzieś zalogowany. Aby uprościć, może być użyteczne, aby utworzyć uchwyt dekoratora. –

9

bardziej uniwersalne rozwiązanie

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

Prosty i elastyczny. +1 – yekta

8
pip install django-nested-inline 

Ten pakiet powinien robić to, co trzeba.

+0

** django-nested-inline ** nie jest (jeszcze?) Obsługiwane w najnowszych wersjach django. Ale możesz rozważyć użycie https://github.com/theatlantic/django-nested-admin, które jest prawie takie samo. – vmonteco

+0

@vmonteco możesz podać mi link do dokumentu, gdzie opisano, jak go używać bez pakietów? –

+1

@OleksandrDashkov http://django-nested-admin.readthedocs.io/en/latest/, na górze strony github. Ale i tak prawdopodobnie i tak trzeba będzie zainstalować pakiet. – vmonteco

2

zagnieżdżone inlines są wyposażone w: https://github.com/BertrandBordage/django-super-inlines/

pip install django-super-inlines 
+0

Próbowałem. Nie pozwala mi dodawać ani usuwać niektórych inline i zmusza mnie do zrobienia 3 nowych obiektów podrzędnych. Nie można go wykorzystać na tym etapie rozwoju. – max

0

użyłem rozwiązania dostarczonego przez @bigzbig (dziękuję).

Chciałem wrócić do pierwszej strony listy raz zmiany zostały zapisane, więc dodał:

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