【问题标题】:How Do I Show Django Admin Change List View of foreign key children?如何显示外键子项的 Django 管理员更改列表视图?
【发布时间】:2011-04-14 11:13:36
【问题描述】:

我正在开发一个模型层次结构为 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 范式中是否有“更好”的方法?

感谢您的帮助!

【问题讨论】:

    标签: django django-admin changelist


    【解决方案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)
    

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

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

    【讨论】:

    • 酷。谢谢你。我唯一要添加到等式中的是一种从管理列表中删除“帐户”的方法,以便只能通过广告系列列表中的链接访问它的列表视图。有什么想法吗?
    【解决方案2】:

    如果我对您的理解正确,您希望将自定义字段 (a callable in your ModelAdmin's list_display) 添加到您的 CampaignAdmin 更改列表视图。

    您的自定义字段将是一个链接,该链接获取您的 change_list 中每个类别的 category.id,并生成一个指向所需的、过滤的 admin view 的链接,在您的情况下这似乎是 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/

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案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 的列表视图中...

        【讨论】:

          最近更新 更多