web-dev-qa-db-fra.com

Django Admin imbriqué en ligne

Il me faut un administrateur imbriqué Django en ligne, Auquel je peux inclure le champ de date en ligne dans un autre en ligne comme ci-dessous.

J'ai les modèles ci-dessous:

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)

et l'administrateur ci-dessous:

class CertificateInline(admin.StackedInline):
    model = Certificate

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

mais je dois inclure le modèle Training_Date en ligne, qui fait partie de Certificate admin inline.

Une idée ? 

38
tunaktunak

Autant que je sache, vous ne pouvez pas avoir un deuxième niveau d'inlines dans l'administrateur Django par défaut.

L'administrateur Django est juste une application Django normale, rien ne vous empêche donc d'implémenter un deuxième niveau de formulaires imbriqués, mais à mon humble avis, ce serait une sorte de conception compliquée à mettre en œuvre. C’est peut-être pour cette raison que rien n’est prévu.

10
Paulo Scardine

Il y a eu un mouvement dans https://code.djangoproject.com/ticket/9025 récemment, mais je ne pouvais pas retenir mon souffle.

Une solution courante consiste à créer un lien entre un premier et un deuxième (ou un deuxième et un troisième) administrateurs en ayant à la fois un ModelAdmin et un Inline pour le même modèle:

Attribuez à ModelAdmin un certificat avec TrainingDate en ligne. Attribuez à CertificateInline un champ "Détails" supplémentaire, qui est un lien vers son formulaire de modification 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)
34
Danny W. Adair

Solution plus universelle 

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)
15
bigzbig
pip install Django-nested-inline

Ce paquet devrait faire ce dont vous avez besoin.

10
s-block

Les inlines imbriquées sont fournies à l'adresse suivante: https://github.com/BertrandBordage/Django-super-inlines/

pip install Django-super-inlines
4
Rick Westera

J'ai utilisé la solution fournie par @bigzbig (merci).

Je voulais aussi revenir à la première page de la liste une fois les modifications sauvegardées, alors ajouté:

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))
2
appdev epiccycles