可能限制过滤器在Django管理中的ManyToMany / Foreign Key对于在另一个模型上定义关系的模型? [英] Possible to limit filters ManyToMany/Foreign Key in Django admin for a model where the relationship is defined on the other model?

查看:121
本文介绍了可能限制过滤器在Django管理中的ManyToMany / Foreign Key对于在另一个模型上定义关系的模型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以标题是有点钝,我知道,但我不能想到一个更简洁的方式来说明。这是一个问题:



我已经为用户类型创建了两个代理模型,这两个代理模型都继承自django.contrib.auth.User。每个都有一个自定义管理器,将查询器限制为属于特定组的项目。具体来说,有一个PressUser是属于新闻组的任何用户和StaffUser,它是除新闻之外的任何其他组中的任何用户。



问题是当我在StaffUsers modeladmin上添加groups到list_filters时,生成的过滤器选项是每个组可用的,包括Press,而不仅仅是StaffUsers可用的组。



我已经在线研究,并提出了一个应该产生我想要的行为的自定义filterspec,但问题是用户模型的groups属性实际上是从组模型应用的相关名称。因此,我无法在我的代理模型中将我的filterspec附加到groups。



有没有其他方法来应用filterspec?或者,是否有更好的方法来过滤默认filterspec返回的项目?

解决方案

所以,我能够解决我的自己的问题对于那些可能遇到类似情况的人,这里是以下步骤:



我采取的方法是修改change_list.html模板,并手动过滤掉我没有的项目不想包括。



首先,向您的ModelAdmin添加一个 changelist_view 方法: / p>

 #myproject / account / admin.py 

class StaffUserAdmin(models.ModelAdmin):$ b $
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 

{%extendsadmin / change_lis t.html%

{%load admin_list%}
{%load i18n%}
{%load account_admin%}

{%块过滤器%}

{%如果cl.has_filters%}
< div id =changelist-filter>
< h2> {%trans'Filter'%}< / h2>
{%for 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



变量规范。标题保存正在过滤的字段的标题。由于我试图改变组过滤器的显示方式,我检查它是否等于'组'。如果是,那么我使用我的自定义模板标签,否则它将返回到默认的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',所以我可以从之前传入过滤的组列表,以及在字典中添加一个新的键,将该列表传递给模板标签的上下文。我还将标签的模板更改为我们即将创建的新模板。



第四,为模板标签创建模板。 p>

 #myproject / templates / admin / auth / group_filter.html 

{%load i18n%}
< h3> {%blocktrans,标题为filter_title%}由{{filter_title}} {%endblocktrans%}< / h3>
< ul>
{%在选择中选择%}
{%if groups.display in groups%}
< li {%if choice.selected%} class =selected{%endif% }>
< a href ={{choice.query_string | iriencode}}> {{choice.display}}< / a>< / li>
{%endif%}
{%endfor%}
< / ul>

这里没有什么大惊喜。我们所做的就是把所有的东西都放在一起。每个选择是一个具有构建过滤器链接所需的所有值的字典。具体来说, choice.display 保存将被过滤的实例的实际名称。显然,我已经设置了一个检查,看看这个值是否在我要过滤的组中过滤的列表中,并且只能呈现链接。




So the title is a bit obtuse, I know, but I couldn't think of a more succinct way to state it. Here's the issue:

I've created two proxy models for "user types", both inheriting from django.contrib.auth.User. Each has a custom manager limiting the queryset to items belonging to a particular Group. Specifically, there's a PressUser which is any user belonging to the "Press" group and StaffUser which is any user in any other group than "Press".

The issue is that when I add 'groups' to list_filters on my StaffUsers modeladmin, the resulting filter options are every group available, including "Press", and not just groups available to StaffUsers.

I've research a bit online and came up with a custom filterspec that should produce the behavior I want, but the problem is that the User model's 'groups' attribute is actually a related_name applied from the Group model. As a result, I can't attach my filterspec to 'groups' in my proxy model.

Is there any other way to apply the filterspec? Alternatively, is there a better approach to filtering the items returned by the default filterspec?

解决方案

So, I was able to solve my own problem. For those that might run into a similar situation, here's the steps:

The approach I took is to modify the change_list.html template and manually filter out the items I didn't want included. There's quite a number of changes to make, though.

First, add a changelist_view method to your ModelAdmin:

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

Basically, all we're doing here is passing in the filtered list of Groups we want to use into the context for the template.

Second, create a change_list.html template for your app.

# 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 %}

This one deserves a little explanation. First, the template tag loads: admin_list is used for the default Django template tag responsible for rendering the filters, admin_list_filter, i18n is used for trans, and account_admin is for my custom template tag (discussed in a sec), admin_list_group_filter.

The variable spec.title holds the title of the field that's being filtered on. Since I'm trying to alter how the Groups filter is displayed, I'm checking if it equals 'groups'. If it does, then I use my custom template tag, otherwise it falls back to the default Django template tag.

Third, we create the template tag. I basically just copied the default Django template tag and made the necessary modifications.

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

The only things that I've changed here are adding a new argument to the method called 'groups' so I can pass in my filtered list of groups from before, as well as adding a new key to the dictionary to pass that list into the context for the template tag. I've also changed the template the tag uses to a new one that we're about to create now.

Fourth, create the template for the template tag.

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

No big surprises here. All we're doing is putting all the pieces together. Each choice is a dictionary with all the values needed to construct the filter link. Specifically, choice.display holds the actual name of the instance that will be filtered by. Obviously enough, I've set up a check to see if this value is in my filtered list of groups I want to show, and only render the link if it is.

So, it's a bit involved, but works remarkably well. Just like that you have a list of filters that is exactly what you want instead of the default ones generated by Django.

这篇关于可能限制过滤器在Django管理中的ManyToMany / Foreign Key对于在另一个模型上定义关系的模型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆