【问题标题】:Django Admin Custom Change List Arguments: Override /?e=1Django 管理员自定义更改列表参数:覆盖 /?e=1
【发布时间】:2011-12-13 18:23:21
【问题描述】:

我正在尝试将自定义参数传递给 Django Admin 更改列表视图,以便以专门的方式过滤列表。我想根据名为“active_pp”的 GET 参数过滤 2 个字段 start_date 和 end_date 的查询集。我已经让过滤器正常工作,但我无法传入一个 GET 查询参数,该参数指定我应该显示过滤结果还是正常结果。

我知道,出于安全考虑,Django Admin 会过滤掉任何传递给它的与指定模型字段无关的查询参数;发现错误参数后,管理员将用户重定向到当前视图,但将 GET 查询参数替换为 e=1。我想将我的自定义“active_pp”参数列入白名单,这样页面就不会被重定向并且我可以使用该参数。

这里是 admin.py 中带有查询集自定义的 ModelAdmin 示例。

class FeaduredAdmin(admin.ModelAdmin): 

    ....

    def get_changelist(self, request, **kwargs):
        from django.contrib.admin.views.main import ChangeList

        # Try to get the 'active_pp' query parameter
        active_pp = request.GET.get('active_pp',None)

        # Define a custom ChangeList class with a custom queryset
        class ActiveChangeList(ChangeList):
            def get_query_set(self, *args, **kwargs):
                now = datetime.datetime.now()
                qs = super(ActiveChangeList, self).get_query_set(*args, **kwargs)
                return qs.filter((Q(start_date=None) | Q(start_date__lte=now))
                             & (Q(end_date=None) | Q(end_date__gte=now)))

        # use the custom ChangeList class if the parameter exists
        if active_pp:
             return ActiveChangeList

        return ChangeList

有谁知道如何将传递给 change_list 的自定义 GET 查询字符串参数列入白名单?

感谢您的阅读和考虑, 乔

更新:

使用 Uvasal 提供的链接,我能够正确地将 GET 参数列入白名单。

class ActiveFilterAminForm(forms.Form):
    active_pp = forms.CharField()

class FeaduredAdmin(admin.ModelAdmin): 

    ....

    # Based on: http://djangosnippets.org/snippets/2322/
    advanced_search_form = ActiveFilterAminForm()

    def get_changelist(self, request, **kwargs):

        from django.contrib.admin.views.main import ChangeList
        active_pp = self.other_search_fields.get('active_pp',None)
        # now we have the active_pp parameter that was passed in and can use it.

        class ActiveChangeList(ChangeList):

            def get_query_set(self, *args, **kwargs):
                now = datetime.datetime.now()
                qs = super(ActiveChangeList, self).get_query_set(*args, **kwargs)
                return qs.filter((Q(start_date=None) | Q(start_date__lte=now))
                                 & (Q(end_date=None) | Q(end_date__gte=now)))

        if not active_pp is None:
            return ActiveChangeList

        return ChangeList


    def lookup_allowed(self, lookup):
        if lookup in self.advanced_search_form.fields.keys():
            return True
        return super(MyModelAdmin, self).lookup_allowed(lookup)


    def changelist_view(self, request, extra_context=None, **kwargs):
        self.other_search_fields = {} 
        asf = self.advanced_search_form
        extra_context = {'asf':asf}

        request.GET._mutable=True

        for key in asf.fields.keys():
            try:
                temp = request.GET.pop(key)
            except KeyError:
                pass 
            else:
                if temp!=['']: 
                    self.other_search_fields[key] = temp 

        request.GET_mutable=False
        return super(FeaduredProductAdmin, self)\
               .changelist_view(request, extra_context=extra_context)

【问题讨论】:

  • 这似乎是一个足够有用的功能,可以提供适当的 DRY django 支持。
  • 请注意,对于更高版本的 Django,您需要将其更新为“get_queryset”而不是“get_query_set”

标签: django filter arguments admin querystringparameter


【解决方案1】:

我认为您只需将自定义过滤器字段放在 Advanced Search Django Snippet 中所述的 search_fields 类变量中。

您应该也可以修改 sn-p 以支持日期范围。

【讨论】:

  • 感谢 Uvasal。您提供的链接确实有帮助。我已经根据您提供的内容使用实现更新了上面的代码。 - 乔
【解决方案2】:

总而言之,这是上面使用的未记录的 hack:

设置request.GET._mutable = True,然后设置request.GET.pop() 关闭您正在使用的自定义 GET 参数。

【讨论】:

    【解决方案3】:

    我知道这是一篇旧帖子,但刚好遇到了这个需求,并发现了一个非常简短的解决方案,我想我会分享。这里的关键是创建一个不影响查询集的过滤器,并接受在查找中传递给它的任何内容作为有效选项。类似于以下内容:

    from django.contrib.admin import SimpleListFilter    
    
    class PassThroughFilter(SimpleListFilter):
        title = ''
        parameter_name = 'pt'
        template = 'admin/hidden_filter.html'
    
        def lookups(self, request, model_admin):
            return (request.GET.get(self.parameter_name), ''),
    
        def queryset(self, request, queryset):
            return queryset
    

    hidden_filter 模板为空白以防止向过滤器区域添加任何内容,lookups 方法将始终返回我为pt 参数输入的任何内容作为有效的过滤器条目。这将防止在页面加载时弹出?e=1 错误。

    这可以被任何管理员重复使用,使用pt 参数。如果您需要为单个管理员传递多个参数,那么只需将其子类化为单独的过滤器并使用您需要的任何参数覆盖parameter_name。这将具有允许查询字符串中的这些参数而不影响查询集或显示在过滤器列中的效果,然后您可以将它们用于您在其他地方需要它们的任何目的。

    希望这对以后的人有所帮助。

    【讨论】:

    • 100% 最佳解决方案!
    【解决方案4】:

    我已经简化了接受的解决方案 这将不起作用,因为 ModelAdmin 实例在请求之间重用,并且 self.active_pp 存储先前的值,例如change_view请求

    class FeaduredAdmin(admin.ModelAdmin):
        ...
    
        def get_queryset(self, request):
            qs = super().get_queryset(request)
            if self.active_pp:
                qs = qs.filter(...)
            return qs
    
        def changelist_view(self, request, extra_context=None):
            if request.GET:
                request.GET._mutable=True
                try:
                    self.active_pp = request.GET.pop('pp')[0]
                except KeyError:
                    self.active_pp = None
                request.GET_mutable=False
            return super().changelist_view(request, extra_context=extra_context)
    

    此解决方案有意使pp 不参与其他管理过滤器。如果您需要 pp 被其他过滤器认可,请使用 @meesterguyperson 解决方案。

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 2012-03-23
      • 1970-01-01
      • 2019-07-09
      • 1970-01-01
      • 2016-09-04
      • 1970-01-01
      • 1970-01-01
      • 2016-04-27
      相关资源
      最近更新 更多