[英]Possible to limit filters ManyToMany/Foreign Key in Django admin for a model where the relationship is defined on the other model?
所以我知道標題有點晦澀難懂,但是我想不出一種更簡潔的陳述方式。 這是問題所在:
我為“用戶類型”創建了兩個代理模型,它們都繼承自django.contrib.auth.User。 每個都有一個自定義管理器,將查詢集限制為屬於特定組的項目。 具體來說,有一個PressUser是屬於“ Press”組的任何用戶,而StaffUser是屬於除“ Press”之外的任何其他組的任何用戶。
問題是,當我在StaffUsers模型管理員的list_filters中添加“組”時,生成的過濾器選項是每個可用組,包括“ Press”,而不僅是可供StaffUsers使用的組。
我已經在網上進行了一些研究,並提出了一個自定義filterspec,該規范可以產生我想要的行為,但是問題是User模型的'groups'屬性實際上是從Group模型應用的related_name。 結果,我無法將我的filterspec附加到代理模型中的“組”。
還有其他方法可以應用filterspec嗎? 或者,是否有更好的方法來過濾默認filterspec返回的項目?
因此,我能夠解決自己的問題。 對於可能遇到類似情況的步驟,請按以下步驟操作:
我采用的方法是修改change_list.html模板並手動過濾掉我不想包含的項目。 但是,需要進行很多更改。
首先,向您的ModelAdmin添加一個changelist_view
方法:
# myproject/account/admin.py
class StaffUserAdmin(models.ModelAdmin):
...
def changelist_view(self, request, extra_context=None):
groups = Group.objects.exclude(name__in=['Press',]).values_list('name')
extra_context = {
'groups': [x[0] for x in groups],
}
return super(StaffUserAdmin, self).changelist_view(request,
extra_context=extra_context)
基本上,我們在這里要做的就是將要使用的組的過濾列表傳遞到模板的上下文中。
其次,為您的應用程序創建一個change_list.html模板。
# myproject/templates/admin/auth/staffuser/change_list.html
{% extends "admin/change_list.html" %}
{% load admin_list %}
{% load i18n %}
{% load account_admin %}
{% block filters %}
{% if cl.has_filters %}
<div id="changelist-filter">
<h2>{% trans 'Filter' %}</h2>
{% for spec in cl.filter_specs %}
{% ifequal spec.title 'group' %}
{% admin_list_group_filter cl spec groups %}
{% else %}
{% admin_list_filter cl spec %}
{% endifequal %}
{% endfor %}
</div>
{% endif %}
{% endblock filters %}
這個值得一點解釋。 首先,將加載模板標簽: admin_list
用於負責渲染過濾器的默認Django模板標簽, admin_list_filter
, i18n
用於trans
, account_admin
用於我的自定義模板標簽(將在admin_list_group_filter
秒鍾內討論) admin_list_group_filter
。
變量spec.title
包含要過濾的字段的標題。 由於我試圖更改“組”過濾器的顯示方式,因此我正在檢查它是否等於“組”。 如果是這樣,那么我將使用我的自定義模板標簽,否則,它將使用默認的Django模板標簽。
第三,我們創建模板標簽。 我基本上只是復制了默認的Django模板標簽並進行了必要的修改。
# myproject/account/templatetags/account_admin.py
from django.template import Library
register = Library()
def admin_list_group_filter(cl, spec, groups):
return {'title': spec.title, 'choices' : list(spec.choices(cl)), 'groups': groups }
admin_list_group_filter = register.inclusion_tag('admin/auth/group_filter.html')(admin_list_group_filter)
我在這里所做的唯一更改是在名為“ groups”的方法中添加了一個新參數,這樣我就可以傳入之前過濾過的組列表,並向字典中添加一個新鍵以將該列表傳遞到模板標記的上下文。 我還將標簽使用的模板更改為我們現在要創建的新模板。
第四,為template標簽創建模板。
# myproject/templates/admin/auth/group_filter.html
{% load i18n %}
<h3>{% blocktrans with title as filter_title %} By {{ filter_title }} {% endblocktrans %}</h3>
<ul>
{% for choice in choices %}
{% if choice.display in groups %}
<li{% if choice.selected %} class="selected"{% endif %}>
<a href="{{ choice.query_string|iriencode }}">{{ choice.display }}</a></li>
{% endif %}
{% endfor %}
</ul>
這里沒有什么大驚喜。 我們要做的就是將所有部分放在一起。 每個choice
都是一個字典,其中包含構造過濾器鏈接所需的所有值。 具體來說, choice.display
保存將被其過濾的實例的實際名稱。 顯然,我已經進行了檢查,以查看此值是否在我要顯示的組的篩選列表中,並且僅在顯示鏈接時才顯示。
因此,雖然有點復雜,但是效果很好。 就像這樣,您將擁有一個正是您想要的過濾器列表,而不是Django生成的默認過濾器。
我要馬上告訴你,我從來沒有做過這件事,所以要加一點鹽。
我會建議將覆蓋get_changelist
您ModelAdmin
,以返回自定義ChangeList
類,您可以在某處定義admin
模塊。
您的自定義ChangeList
類將僅覆蓋get_filters
,因此您可以將自定義FilterSpec
映射到group
字段。
您可能會感興趣的另一件事是功能請求票證中的補丁程序,用於指定自定義過濾器規格。 最新的補丁程序不適用於Django 1.3rc1,盡管@ bendavis78最近發布了他正在開發一個新補丁程序的信息,但是取決於您的Django版本,它可能會完全適用。
看起來幾乎沒錯過過將其納入1.3里程碑的工作,所以我認為一旦Django 1.4投入使用,它就會進入主流。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.