Django 管理员自定义更改列表参数:覆盖 /?e=1
我正在尝试将自定义参数传递给 Django 管理更改列表视图,以便我可以以专门的方式过滤列表。我想根据名为“active_pp”的 GET 参数过滤 2 个字段(start_date 和 end_date)上的查询集。我已经使过滤正常工作,但无法传入指定是否应显示过滤结果或正常结果的 GET 查询参数。
我知道,出于安全考虑,Django 管理员会过滤掉传递给它的任何与指定模型字段无关的查询参数;一旦发现错误的参数,管理员会将用户重定向到当前视图,但将 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查询字符串参数列入白名单?
感谢您的阅读和考虑, Joe
更新:
使用 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)
I'm trying to pass in a custom argument to the Django Admin change list view so I can filter the list in a specialized way. I'd like to filter the queryset on 2 fields, start_date and end_date, based on the GET parameter called 'active_pp'. I've gotten the filtering to work correctly, but I'm not able to pass in a GET query parameter that specifies whether I should display the filtered results or the normal results.
I know that, due to security, the Django Admin filters out any query parameters passed to it that aren't related to specified model fields; upon finding bad arguments, the admin redirects the user to the current view but replaces the GET query parameters with e=1. I'd like to whitelist my custom 'active_pp' parameter so the page won't be redirected and I'll be able to use the parameter.
Here is an example of the ModelAdmin in admin.py with the queryset customization.
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
Does anyone know how to whitelist custom GET querystring arguments passed to the change_list?
Thanks for reading and for your consideration,
Joe
UPDATE:
Using Uvasal's provided links, I was able to properly whitelist the GET parameter.
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)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我知道这是一篇旧帖子,但刚刚遇到了这个需要,并发现了一个非常简短的解决方案,我想我会分享。这里的关键是创建一个不影响查询集并接受查找中传递给它的任何内容作为有效选项的过滤器。类似于以下内容:
hidden_filter
模板为空,以防止向过滤区域添加任何内容,并且lookups
方法将始终返回我为pt 输入的任何内容
参数作为有效的过滤器条目。这将防止页面加载时弹出?e=1
错误。任何管理员都可以使用
pt
参数重复使用它。如果您需要为单个管理员传递多个参数,则只需将其子类化为单独的过滤器,并使用您需要的任何参数覆盖parameter_name
即可。这将具有允许查询字符串中的这些参数的效果,而不影响查询集或显示在过滤器列中,然后您可以将它们用于其他地方需要它们的任何目的。希望这可以帮助某人。
I know this is an old post, but just ran into a need for this and discovered a very short and simple solution that I thought I would share. Key here is to make a filter that doesn't affect the queryset and accepts anything passed to it in the lookups as valid option. Something like the following:
The
hidden_filter
template is blank to prevent adding anything to the filter area, and thelookups
method will always return whatever I have entered for thept
parameter as a valid filter entry. This will prevent the?e=1
error from popping up as the page loads.This can be reused with any admin, using the
pt
parameter. If you need to pass multiple parameters for a single admin, then just subclass this into separate filters and overrideparameter_name
with whatever parameters you need. This will have the effect of allowing those parameters in the query string without affecting the queryset or showing up in the filter column, and you can then use them for whatever purpose you needed them elsewhere.Hope this helps someone down the road.
我认为您只需将自定义过滤器字段放入 search_fields 类变量中,如高级搜索中所述姜戈片段。
您应该能够修改代码片段以支持日期范围。
I think you just need to put your custom filter fields in the search_fields class variable as outlined in the Advanced Search Django Snippet.
You should be able to modify the snippet to support date ranges as well.
总之,这里是上面使用的未记录的黑客:
设置
request.GET._mutable = True
,然后request.GET.pop()
关闭自定义 GET 参数你正在使用。In summary, here is the undocumented hack used above:
set
request.GET._mutable = True
, thenrequest.GET.pop()
off the custom GET argument(s) you are using.我已经简化了接受的解决方案这将不起作用,因为 ModelAdmin 实例在请求之间重用,并且 self.active_pp 存储例如change_view
请求的先前值:这解决方案故意使
pp
不参与其他管理过滤器。如果您需要pp
受到其他过滤器的尊重,请使用 @meesterguyperson 解决方案。I have simplified accepted solutionThis will not work as ModelAdmin instance is reused between requests and self.active_pp stores previous value for e.g.change_view
request:This solution intentionally makes
pp
not participate in other admin filters. If you needpp
to be honored by other filters use @meesterguyperson solution.