Reputation: 2365
I'd like to create a view function that simulates the user getting a form at url
, setting one of the form's input variables (my_flag
) and submitting that form. I've tried two different approaches and both have failed.
Approach 1: use python requests to get and post to url
def simulate_post(request):
url = request.build_absolute_uri(reverse('my_app:form_view', args=[666]))
response = requests.get(url)
csrftoken = response.cookies['csrftoken']
print("TOKEN =", csrftoken)
response = requests.post(url, data={'my_flag': True, 'csrftoken': csrftoken}, headers={'Referer': url})
return response
This approach fails as follows. Obviously I'm not even passing on the CSRF token successfully:
TOKEN = EXFI2xoKxHounDIRnqdrPwLpdXGe3zuZATErKINTuxJsgzV7Oj6lPP6kzsjQVc7z
Forbidden (CSRF cookie not set.): /form_view/666/
[12/Feb/2021 16:44:02] "POST /form_view/666/ HTTP/1.1" 403 2868
Internal Server Error: /simulate_post/
Traceback (most recent call last):
File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/utils/deprecation.py", line 96, in __call__
response = self.process_response(request, response)
File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/middleware/clickjacking.py", line 26, in process_response
if response.get('X-Frame-Options') is not None:
AttributeError: 'Response' object has no attribute 'get'
Approach 2: use RequestFactory
def simulate_post(request):
url = request.build_absolute_uri(reverse('my_app:form_view', args=[666]))
factory = RequestFactory()
factory.user = request.user
response = factory.get(url)
response = factory.post(url, data={'my_flag': True})
return response
This approach fails as follows:
Internal Server Error: /simulate_post/
Traceback (most recent call last):
File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/utils/deprecation.py", line 96, in __call__
response = self.process_response(request, response)
File "/Users/me/.local/share/virtualenvs/myapp-MCS7ouoX/lib/python3.8/site-packages/django/middleware/clickjacking.py", line 26, in process_response
if response.get('X-Frame-Options') is not None:
AttributeError: 'WSGIRequest' object has no attribute 'get'
It appears that I'm not returning a proper response in either case from my simulated POST. How do I get this to work?
Update: Approach 3 [incomplete]
Pursuing the suggestion of @schillingt and Iain to refactor out the guts of the search/form view I'm trying to leverage, here's a third potential approach, if I knew how to proceeded.
Making the first HTTP request, the GET, basically is equivalent to something like this:
context = search_context(request, data)
return render(request, 'myapp/display.html', context)
That context
includes a form
variable which is the form for the search. If I could set the form as I wanted and turn request
into a POST it would produce what I needed. Not sure how though...
Upvotes: 0
Views: 315
Reputation: 32244
You can use resolve
to get the actual view function that will be called for the given url. Passing a POST request generated from a RequestFactory
to the view returned by resolve
should work
from django.shortcuts import reverse
from django.test import RequestFactory
from django.urls import resolve
def simulate_post(request):
url = reverse('my_app:form_view', args=[666])
factory = RequestFactory()
post_request = factory.post(url, data={'my_flag': True})
resolved = resolve(url)
return resolved.func(post_request, *resolved.args, **resolved.kwargs)
Upvotes: 1
Reputation: 13731
The name of the input is csrfmiddlewaretoken
.
def simulate_post(request):
url = request.build_absolute_uri(reverse('my_app:form_view', args=[666]))
response = requests.get(url)
csrftoken = response.cookies['csrftoken']
print("TOKEN =", csrftoken)
response = requests.post(url, data={'my_flag': True, 'csrfmiddlewaretoken': csrftoken}, headers={'Referer': url})
return response
Upvotes: 0