Имитация POST-запроса в Django - PullRequest
4 голосов
/ 21 февраля 2012

Предположим, у меня есть следующий URL: /valid/django/app/path/?foo=bar&spam=eggs

Я могу смоделировать запрос на этот URL в Django следующим образом:

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)

Однако я хотел бы включитьпараметры для включенного представления, так что объекты request.REQUEST и request.GET будут также включать foo и spam

Я не понимаю, как я могу сделать это чисто;насколько я понимаю словари request.GET и request.REQUEST неизменны, поэтому я не могу просто сделать что-то вроде:

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)

Или я получу сообщение об ошибке

Этот экземпляр QueryDict является неизменным

для объекта request.GET и

У объекта 'MergeDict' нет атрибута 'update'

для объекта request.REQUEST

В случае, если кому-то интересно, почему я хочу сделать это: я хочу разрешить пользователям заполнять форму, а затем, когда они отправляют, если они не вошли в нееотправляет их в форму входа, которая включает в себя оригинальный URL-адрес в скрытом поле.После входа в систему, вместо того, чтобы перенаправлять обратно на эту ссылку (что было бы запросом GET), я хочу, чтобы он вызывал исходное представление с переменными запроса, которые у него были изначально, чтобы он мог использовать тот же запрос POST.

И поэтому, конечно, в процессе я также просто заинтересован в том, можно ли имитировать запрос POST / GET для представления Django, если указан действительный URL-адрес для сайта.

Ответы [ 2 ]

14 голосов
/ 21 февраля 2012

request.GET / POST являются QueryDict экземплярами.Согласно документации на QueryDict , действительно есть "неизменяемые" , если только вы не клонируете их :

Экземпляры QueryDict являются неизменяемыми, если вы не создаете копию () из них.Это означает, что вы не можете изменять атрибуты request.POST и request.GET напрямую.

Вы можете копировать, обновлять и переназначать QueryDicts следующим образом:

ipdb> request.GET
<QueryDict: {u'x': [u'1']}>
ipdb> request.POST
<QueryDict: {}>
ipdb> request.REQUEST
MergeDict(<QueryDict: {}>, <QueryDict: {u'x': [u'1']}>)
ipdb> new_post = request.POST.copy()
ipdb> new_post.update(request.GET)
ipdb> request.POST = new_post
ipdb> request.POST
<QueryDict: {u'x': [u'1']}>
ipdb> request.GET
<QueryDict: {u'x': [u'1']}>
ipdb> request.REQUEST
MergeDict(<QueryDict: {}>, <QueryDict: {u'x': [u'1']}>)

Хитрость в обновлении MergeDict заключается в переопределении атрибута dicts следующим образом:

ipdb> request.REQUEST
MergeDict(<QueryDict: {}>, <QueryDict: {u'x': [u'1']}>)
ipdb> request.REQUEST.dicts = (request.POST, request.GET)
ipdb> request.REQUEST
MergeDict(<QueryDict: {u'x': [u'1']}>, <QueryDict: {u'x': [u'1']}>)

Обратите внимание, что MergeDict определяется в модуле django.utils.datastructures и создается в django.core.handlers.wsgi (и django.core.handlers.modpython) следующим образом: self._request = datastructures.MergeDict(self.POST, self.GET).

DISCLAMER : MergeDict не задокументирован, однажды сломается и, вероятно, даже убьет некоторых котят .Используйте по своему усмотрению и со своими собственными котятами.Тем не менее, мне нравится ваш вариант использования, это довольно хорошая идея.

0 голосов
/ 25 февраля 2015

Это правда, чем request.GET / POST являются неизменяемыми объектами, но вы на самом деле можете сделать их изменяемыми (это потенциально опасно) и изменить их напрямую, например:

...