Simulando uma solicitação POST no Django

Vamos supor que eu tenho o seguinte url: /valid/django/app/path/?foo=bar&spam=eggs

Eu posso simular um pedido para este URL no Django assim:

 from django.shortcuts import render from django.core.urlresolvers import resolve def simulate(request, url=None, template_name="not_important.html"): if url: dv = resolve(url.split('?')[0]) return dv.func(request, *dv.args, **dv.kwargs) else: return render(request, template_name) 

No entanto, gostaria de include os parâmetros na exibição incluída, para que os objects request.REQUEST e request.GET também incluam foo e spam

Eu não vejo como posso fazer isso de forma limpa; Tanto quanto eu entendo os dictionarys request.GET e request.REQUEST são imutáveis, então eu não posso simplesmente fazer algo como:

 import urlparse def simulate(request, url=None, template_name="not_important.html"): if url: dv = resolve(url.split('?')[0]) qs = "".join(url.split('?')[1:]) if qs: request.REQUEST.update(urlparse.parse_qs(qs)) request.GET.update(urlparse.parse_qs(qs)) return dv.func(request, *dv.args, **dv.kwargs) else: return render(request, template_name) 

Ou eu vou pegar a mensagem de erro

Esta instância QueryDict é imutável

para o object request.GET e

Objeto ‘MergeDict’ não tem atributo ‘update’

para o object request.REQUEST

Caso alguém esteja se perguntando por que eu quero fazer isso: eu quero permitir que os usuários preencham um formulário e, quando eles enviarem, se eles não estiverem logados, ele os envia para um formulário de login que inclua o URL original em um formulário. campo oculto. Após o login, em vez de redirect de volta para esse link (o que seria uma solicitação GET), eu quero chamar a visualização original, com as variables ​​de solicitação originalmente, para que ela possa usar a mesma solicitação POST.

E é claro que também estou interessado em saber se seria possível simular uma solicitação POST / GET para uma visualização do Django quando for dada uma URL válida para o site.

request.GET / POST são instâncias de QueryDict . De acordo com a documentação do QueryDict , há de fato “imutável”, a menos que você os clone :

As instâncias de QueryDict são imutáveis, a menos que você crie uma cópia () delas. Isso significa que você não pode alterar atributos de solicitação.POST e request.GET diretamente.

Você pode copiar, atualizar e reatribuir QueryDicts como tal:

 ipdb> request.GET  ipdb> request.POST  ipdb> request.REQUEST MergeDict(, ) ipdb> new_post = request.POST.copy() ipdb> new_post.update(request.GET) ipdb> request.POST = new_post ipdb> request.POST  ipdb> request.GET  ipdb> request.REQUEST MergeDict(, ) 

O truque para atualizar o MergeDict é sobrescrever seu atributo dicts como tal:

 ipdb> request.REQUEST MergeDict(, ) ipdb> request.REQUEST.dicts = (request.POST, request.GET) ipdb> request.REQUEST MergeDict(, ) 

Note que MergeDict é definido no módulo django.utils.datastructures , e instanciado em django.core.handlers.wsgi (e django.core.handlers.modpython) como tal: self._request = datastructures.MergeDict(self.POST, self.GET) .

DISCLAMER : MergeDict não está documentado, vai quebrar um dia e provavelmente até matar alguns gatinhos . Use a seu próprio critério e com seus próprios gatinhos. Dito isso, eu gosto do seu caso de uso, é uma boa ideia.

É verdade que request.GET / POST são objects imutáveis, mas você pode realmente torná-los mutáveis ​​(isso é potencialmente perigoso) e alterá-los diretamente, assim:

 request.GET._mutable = True # make some changes, for example delete something inside if 'var_name' in request.GET: del request.GET['var_name'] request.GET._mutable = False