djangodjango-adminchangelist

How Do I Show Django Admin Change List View of foreign key children?


I'm working on an app with a Model hierarchy of Campaign > Category > Account. Ideally, I'd like users to be able to click on a link in the campaign admin list view and go to a URL like "/admin/myapp/campaign/2/accounts/" which will show a Django admin view with all the handy ChangeList amenities but which is filtered to show just the accounts in categories in the specified campaign (ie. Account.object.filter(category__campaign__id = 2)). (Note, categories themselves I'm happy to just be "filters" on this accounts list view).

I can't seem to find any reference to a way to mimic this item-click-goes-to-list-of-foriegn-key-children approach that is common in many other frameworks.

Is it possible? Is there a "better" approach in the django paradigm?

thanks for any help!


Solution

  • This was an interesting question so I whipped up a sample app to figure it out.

    # models.py
    from django.db import models
    
    class Campaign(models.Model):
        name = models.CharField(max_length=20)
    
        def __unicode__(self):
            return unicode(self.name)
    
    class Category(models.Model):
        campaign = models.ForeignKey(Campaign)
        name = models.CharField(max_length=20)
    
        def __unicode__(self):
            return unicode(self.name)
    
    class Account(models.Model):
        category = models.ForeignKey(Category)
        name = models.CharField(max_length=20)
    
        def __unicode__(self):
            return unicode(self.name)
    
    # admin.py
    from django.contrib import admin
    from models import Campaign, Category, Account
    
    class CampaignAdmin(admin.ModelAdmin):
        list_display = ('name', 'related_accounts', )
    
        def related_accounts(self, obj):
            from django.core import urlresolvers
            url = urlresolvers.reverse("admin:<yourapp>_account_changelist")
            lookup = u"category__campaign__exact"
            text = u"View Accounts"
            return u"<a href='%s?%s=%d'>%s</a>" % (url, lookup, obj.pk, text)
        related_accounts.allow_tags = True
    admin.site.register(Campaign, CampaignAdmin)
    admin.site.register(Category)
    
    class AccountAdmin(admin.ModelAdmin):
        list_display = ('category', 'name')
        list_filter = ('category__campaign',)
    admin.site.register(Account, AccountAdmin)
    

    You'll need to replace with the name of your app where the Account ModelAdmin lives.

    Note: the list_filter on the AccountAdmin is required since Django 1.2.4, Django 1.1.3 and Django 1.3 beta 1, which introduced protection from arbitrary filtering via URL parameter in the admin.