How to show Django admin change list View children with foreign key?

I am working on an application with a campaign model hierarchy> Category> Account. Ideally, I would like users to be able to click on the link in the view of the list of campaign administrators and go to the URL, for example "/ admin / myapp / campaign / 2 / accounts /", which will display the django admin view with everyone but they filtered to show only accounts in the categories of the specified campaign (for example, Account.object.filter (category_campaign_id = 2)). (Note the categories themselves. I'm happy to just be the "filters" on this list of account lists).

I can't seem to find a link to the imitation of this click-to-list-of-foriegn-key-children element, which is common in many other environments.

Is it possible? Is there a β€œbetter” approach in the django paradigm?

Thanks for any help!

+4
source share
4 answers

This was an interesting question, so I hacked an example application to understand it.

# 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 will need to replace the name of your application in which the ModelAdmin account will run.

Note: the list_filter in AccountAdmin is required with Django 1.2.4, Django 1.1.3 and Django 1.3 beta 1, which introduced protection against arbitrary filtering through the URL parameter in admin.

+4
source

If you understand correctly, you want to add a custom field ( called in your ModelAdmin list_display list ) to your change list in the CampaignAdmin campaign.

Your custom field will be a link that accepts the category.id of each category in your change list and creates a link to the desired, filtered admin view , which is apparently an account-change_list in your case:

 admin/yourproject/account/?category__id__exact=<category.id> 

Assuming the category is a field in your campaign model, you can add the following method to your CampaignAdmin:

 def account_link(self, obj): return '<a href="/admin/yourproject/account/?category__id__exact=%s">Accounts</a>' % (obj.category.id) account_link.allow_tags = True 

And then add it to the admin list_display parameter:

 list_display = ('account_link', ...) 

It depends a little on your data model.

If you want to create a permanent, filtered change list view that suits your needs, you can take a look at this article: http://lincolnloop.com/blog/2011/jan/11/custom-filters-django-admin/

+1
source

Other solutions do not pay attention to the filters that you have already applied. They are part of the query string, and I also wanted to keep them.

First you need to get a link to the request, you can do this by wrapping changelist_view or queryset like me:

 class AccountAdmin(ModelAdmin): model = Account list_display = ('pk', 'campaign_changelist') # ... def queryset(self, request): self._get_params = request.GET return super(AccountAdmin, self).queryset(request) def campaign_changelist(self, obj): url = reverse('admin:yourapp_account_changelist') querystring = self._get_params.copy() querystring['campaign__id__exact'] = obj.campaign.pk return u'<a href="{0}?{1}">{2}</a>'.format( url, querystring.urlencode(), obj.campaign) campaign_changelist.allow_tags = True 

And something like this will give you a filter inside the lines of the change list. Really helpful .:-)

+1
source

These are good decisions. I did not know about autofilter by the URL paradigm. Here's another one I found that allows you to use a custom URL scheme:

 from consensio.models import Account from django.contrib import admin from django.conf.urls.defaults import patterns, include, url class AccountAdmin(admin.ModelAdmin): campaign_id = 0; def campaign_account_list(self, request, campaign_id, extra_context=None): ''' First create your changelist_view wrapper which grabs the extra pattern matches ''' self.campaign_id = int(campaign_id) return self.changelist_view(request, extra_context) def get_urls(self): ''' Add your url patterns to get the foreign key ''' urls = super(AccountAdmin, self).get_urls() my_urls = patterns('', (r'^bycampaign/(?P<campaign_id>\d+)/$', self.admin_site.admin_view(self.campaign_account_list)) ) return my_urls + urls def queryset(self, request): ''' Filter the query set based on the additional param if set ''' qs = super(AccountAdmin, self).queryset(request) if (self.campaign_id > 0): qs = qs.filter(category__campaign__id = self.campaign_id) return qs 

And plus you will need to include the URL link in the CampaignAdmin list ...

0
source

Source: https://habr.com/ru/post/1348077/


All Articles