4

我正在开发一个模型层次结构为 Campaign > Category > Account 的应用程序。理想情况下,我希望用户能够单击活动管理列表视图中的链接并转到“/admin/myapp/campaign/2/accounts/”之类的 URL,这将显示一个 Django 管理视图,其中包含所有方便的 ChangeList 便利设施,但经过过滤以仅显示指定广告系列中类别中的帐户(即。Account.object.filter(category__campaign__id = 2))。(请注意,类别本身我很高兴只是此帐户列表视图上的“过滤器”)。

我似乎找不到任何参考来模仿这种在许多其他框架中很常见的 item-click-goes-to-list-of-foriegn-key-children 方法。

是否可以?django 范式中是否有“更好”的方法?

谢谢你的帮助!

4

4 回答 4

4

这是一个有趣的问题,所以我创建了一个示例应用程序来解决这个问题。

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

您需要替换为 Account ModelAdmin 所在的应用程序的名称。

注意:从 Django 1.2.4、Django 1.1.3 和 Django 1.3 beta 1 开始,AccountAdmin 上的 list_filter 是必需的,它们通过管理员中的 URL 参数引入了防止任意过滤的保护。

于 2011-04-14T13:36:57.830 回答
1

如果我理解正确,您想将自定义字段(ModelAdmin 的 list_display 中的可调用字段)添加到您的 CampaignAdmin change_list 视图。

您的自定义字段将是一个链接,该链接获取您的 change_list 中每个类别的 category.id 并生成一个指向所需的过滤管理视图的链接,在您的情况下,这似乎是 account-change_list :

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

假设 category 是您的 Campaign-Model 上的一个字段,您可以将以下方法添加到您的 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', ...) 

不过,这有点取决于您的数据模型。

如果你想创建一个永久的、过滤的 change_list 视图来满足你的需要,你可以看看这篇文章: http: //lincolnloop.com/blog/2011/jan/11/custom-filters-django-admin/

于 2011-04-14T12:07:51.390 回答
1

其他解决方案不会关注您已经应用的过滤器。它们是查询字符串的一部分,我也想保留它们。

首先,您需要获取对请求的引用,您可以通过包装changelist_viewqueryset像我一样做到这一点:

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

类似的东西会给你一个更改列表行内的过滤器。真的很有帮助。:-)

于 2013-02-03T22:51:13.217 回答
0

这些都是很好的解决方案。我不知道 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 的列表视图中......

于 2011-04-16T15:32:19.330 回答