如何显示外键子项的 Django Admin 更改列表视图?

发布于 2024-10-31 22:09:44 字数 422 浏览 4 评论 0原文

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

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

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

感谢您的帮助!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

寒冷纷飞旳雪 2024-11-07 22:09:44

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

# 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 参数进行任意过滤的保护。

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.

汐鸠 2024-11-07 22:09:44

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

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

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

假设类别是您的营销活动模型上的一个字段,您可以添加以下内容方法到您的 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/

If i understand you correctly, you want to add a custom field (a callable in your ModelAdmin's list_display) to your CampaignAdmin change_list view.

Your custom field would be a link that takes the category.id of each category in your change_list and generates a link to the desired, filtered admin view, which seems to be the account-change_list in your case:

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

Assuming category is a field on your Campaign-Model you could add the follwoing 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 you add it to the admin's list_display option:

list_display = ('account_link', ...) 

It depends a bit on your data model though.

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

辞慾 2024-11-07 22:09:44

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

首先,您需要获取对请求的引用,您可以像我一样通过包装 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

类似的东西将为您提供更改列表中的过滤器行。真的很有帮助。 :-)

The other solutions don't pay attention to the filters you already have applied. They are part of the query string and I wanted to retain them as well.

First you need to get a reference to the request, you can do that by wrapping changelist_view or queryset as I did:

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 that will give you a filter inside the changelist rows. Really helpful. :-)

感受沵的脚步 2024-11-07 22:09:44

这些都是很好的解决方案。我不知道按 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+)/

此外,您还需要将 URL 链接合并到 CampaignAdmin 的列表视图中...

, 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 的列表视图中...

These are good solutions. I wasn't aware of the auto-filter by url paradigm. Here's another I've discovered which allows you 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+)/

And plus you'd need to incorporate the URL link into CampaignAdmin's list view...

, 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'd need to incorporate the URL link into CampaignAdmin's list view...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文