78

我已经有一个 django 项目,它的逻辑如下:

url: URL?username=name&pwd=passwd

看法:

def func(request):
   dic = request.GET

   username = dic.get("username")
   pwd = dic.get("pwd")

但现在我们需要加密数据。然后,请求变成了这样:

url: URL?crypt=XXXXXXXXXX (XXXXXXXXX 是加密 str 为 "username=name&pwd=passwd")

所以我需要修改每个视图功能。但现在我想在 django 中间件中解密,以防止修改每个视图函数。

但是当我修改 request.GET 时,我收到错误消息“此 QueryDict 实例是不可变的”。我该如何修改它?

4

6 回答 6

124

django.http.QueryDict分配给request.GET且不request.POST可变的对象。

QueryDict您可以通过复制将其转换为可变实例:

request.GET = request.GET.copy()

之后,您将能够修改QueryDict

>>> from django.test.client import RequestFactory
>>> request = RequestFactory().get('/')
>>> request.GET
<QueryDict: {}>
>>> request.GET['foo'] = 'bar'
AttributeError: This QueryDict instance is immutable
>>> request.GET = request.GET.copy()
<QueryDict: {}>
>>> request.GET['foo'] = 'bar'
>>> request.GET
<QueryDict: {'foo': 'bar'}>

这是有意设计的,因此不允许任何应用程序组件编辑源请求数据,因此即使QueryDict再次创建不可变对象也会破坏这种设计。我仍然建议您遵循指南并直接在request中间件中的对象上分配额外的请求数据,尽管这可能会导致您编辑源。

于 2013-09-21T10:47:11.700 回答
66

删除不变性:

if not request.GET._mutable:
   request.GET._mutable = True

# now you can spoil it
request.GET['pwd'] = 'iloveyou'

更新

Django 认可的方式是:request.GET.copy()

根据文档

request.POST 和 request.GET 的 QueryDict 在正常的请求/响应周期中访问时将是不可变的。要获得可变版本,您需要使用 QueryDict.copy()。

没有什么能保证未来的 Django 版本会使用_mutable这比copy()方法有更多的改变机会。

于 2016-07-14T10:49:39.787 回答
8

您不应该使用 GET 来发送用户名和密码,这是不好的做法(因为它会在 URL 栏上显示信息,并且可能会带来安全风险)。相反,使用 POST。另外,我猜您正在尝试对您的用户进行身份验证,并且似乎您正在做太多工作(创建新的中间件)来处理完全内置的东西,以文档中的示例为例:

from django.contrib.auth import authenticate, login

def my_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(username=username, password=password)
    if user is not None:
        if user.is_active:
            login(request, user)
            # Redirect to a success page.
        else:
            # Return a 'disabled account' error message
    else:
        # Return an 'invalid login' error message.

我自己真的很喜欢使用login_required 装饰器,使用起来非常简单。希望有帮助

于 2013-09-21T08:04:26.577 回答
3
request.GET._mutable = True

你需要这个。

def func(request):
   dic = request.GET
   request.GET._mutable = True #to make it editable 
   username = dic.get("username")
   request.GET.pop("pwd")
   request.GET._mutable = False #make it False once edit done
于 2019-12-13T11:33:54.900 回答
0

目前,我有 Django 3.2.2。我需要修改self.request.query_params. 我在评论中读到这里self.request.query_params只是self.request.GET.

首先,我尝试了以下方法:

self.request.GET = self.request.GET.copy()
... modify self.request.GET

self.request.query_params没有改变。

当我明确尝试self.request.query_params = self.request.GETorself.request.query_params = self.request.query_params.copy()时,我得到了AttributeError: can't set attribute.

唯一有效的方法:

self.request.query_params._mutable = True
self.request.query_params['attribute'] = 'needed_value'
self.request.query_params._mutable = False
于 2022-02-02T15:27:06.800 回答
0

您只需要更改 request.data:

def func(request):
   request.data._mutable = True
   dic = request.data
   username = dic['username']
   pwd = dic['pwd']
于 2021-12-15T05:38:57.053 回答