#django #django-admin #changelist
#django #django-admin #список изменений
Вопрос:
Я работаю над приложением с моделью иерархии Кампания> Категория> Учетная запись. В идеале я хотел бы, чтобы пользователи могли щелкнуть ссылку в представлении списка администраторов кампании и перейти по URL-адресу типа «/admin/myapp/campaign/2/ accounts /», который покажет представление администратора Django со всеми удобными функциями списка изменений, но который фильтруется, чтобы показывать только учетные записи в категориях указанной кампании (т. Е. Account.object.filter(category__campaign__id = 2)
). (Обратите внимание, что сами категории я рад быть просто «фильтрами» в этом представлении списка учетных записей).
Кажется, я не могу найти ни одной ссылки на способ имитации этого подхода «щелчок по элементу переходит к списку дочерних элементов», который распространен во многих других фреймворках.
Возможно ли это? Есть ли «лучший» подход в парадигме django?
спасибо за любую помощь!
Ответ №1:
Это был интересный вопрос, поэтому я создал пример приложения, чтобы разобраться в нем.
# 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)
Вам нужно будет заменить его именем вашего приложения, в котором находится учетная запись ModelAdmin.
Примечание: параметр list_filter в AccountAdmin требуется начиная с Django 1.2.4, Django 1.1.3 и Django 1.3 beta 1, в которых введена защита от произвольной фильтрации с помощью параметра URL в admin.
Комментарии:
1. Прохладный. Спасибо. Единственное, что я бы добавил к уравнению, это способ удаления «Учетных записей» из списка администраторов, чтобы к ним можно было получить доступ только через ссылку в списке кампаний. Есть идеи?
Ответ №2:
Если я вас правильно понял, вы хотите добавить пользовательское поле (вызываемое в list_display вашего администратора модели) в представление списка изменений вашего администратора кампании.
Вашим пользовательским полем будет ссылка, которая принимает category.id каждой категории в вашем списке изменений и генерирует ссылку на желаемое отфильтрованное представление администратора, которое, по-видимому, является account-change_list в вашем случае:
admin/yourproject/account/?category__id__exact=<category.id>
Предполагая, что категория — это поле в вашей Модели Campaign, вы могли бы добавить следующий метод в свой 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
А затем вы добавляете его в параметр администратора list_display:
list_display = ('account_link', ...)
Однако это немного зависит от вашей модели данных.
Если вы хотите создать постоянное отфильтрованное представление списка изменений, соответствующее вашим потребностям, вы можете ознакомиться с этой статьей: http://lincolnloop.com/blog/2011/jan/11/custom-filters-django-admin /
Ответ №3:
Другие решения не обращают внимания на фильтры, которые вы уже применили. Они являются частью строки запроса, и я хотел бы также сохранить их.
Сначала вам нужно получить ссылку на запрос, вы можете сделать это, обернув changelist_view
или queryset
, как я сделал:
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
И что-то подобное даст вам фильтр внутри строк списка изменений. Действительно полезно. 🙂
Ответ №4:
Это хорошие решения. Я не знал о парадигме автоматического фильтра по URL. Вот еще один, который я обнаружил, который позволяет вам использовать пользовательскую схему URL:
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
И, кроме того, вам нужно будет включить URL-ссылку в представление списка CampaignAdmin…