Send user data in python requests module - python

I am unable to send the user details along with requests module i had to hard code the user details in the data payload to identify the user.
full_url = ''.join(['http://', get_current_site(request).domain, '/am/reply'])
data = {
'agent_type':'trigger',
'input':platform,
'userid':request.user.id ####==>> had to send userid like this
}
a = requests.get(full_url,params=data)
Is there way to send all general request data using requests.?
And moreover the requests url the destination view i have implemented
def index(request):
if not request.user.is_authenticated:
return HttpResponseRedirect(reverse('login'))
And request.user.id is none when url is reached through requests module
In general how should i validate a request when using requests module

Django uses request and response objects to pass state through the system.
When a page is requested, Django creates an HttpRequest object that contains metadata about the request. Then Django loads the appropriate view, passing the HttpRequest as the first argument to the view function. Each view is responsible for returning an HttpResponse object.
Some of the middleware included in Django’s contrib apps set attributes on the request. If you don’t see the attribute on a request, be sure the appropriate middleware class like authenticationmiddleware,sessionmiddleware.
Following piece of code will give the user.id if and only if the user is authenticated.
def myview(request):
if request.user.is_authenticated:
print request.user.id
else:
... # Do something else.
https://docs.djangoproject.com/en/1.10/ref/request-response/

If I understood your question correctly, You are getting request in one view, and then making a call to other view using requests module. It that case the request object in index view will be totally different because that request was sent from your server where application works, not from user. You can only get data in index view using request.GET.get("userid") and so on. And then if you will need user info, just fetch it again from database using userid. Passing request object to other view using requests library is not possible.

Related

get request data from Flask redirect

I have to create a small web app in Flask which contains an API and also an interface and I'm facing the following problem:
This would be how i handle a GET request:
#app.route('/member/<id>', methods=['GET'])
def member_get(id):
member = cursor.execute(f"select * from members where id={id}").fetchone()
if member is not None:
return to_json(member), 200
else:
return 'Not found', 404
And I would like to create some small forms with which I could do GET,POST,PUT,DELETE operations.
This would be how I get the data from the form:
#app.route('/dashboard', methods=['POST'])
def dashboard_post():
id = request.form['get_id']
return redirect(url_for("member_get",id=id))
My question is how can I get the data from the API method without actually redirecting to that page?
More precise, can I call somehow redirect(url_for("member_get",id=id)) and get the response data directly? (if I print the return of the redirect method it only shows the request status)
I assume one solution would be using the requests module, but is there a way to do it directly in Flask?
First of all, an API should always return a response in a format that is consistent and predictable. The code for member_get returns JSON in case of success but plain text in case of failure. This is not okay. You should return JSON always, with the appropriate HTTP status code. Here you are using 404 to express Not found, this is good.
You can use the jsonify function in Flask for that. And maybe normalize the response, so that is always has the same shape, whether the member ID is found or not.
Otherwise, parsing the response from your API will be harder because it is not consistent depending on the scenario.
Second point, if I understand it right: if you want to invoke the route '/member/' from within your API, you could simply do:
return member_get(id)
You call the function that is attached to the route, not the route itself. Of course you could actually fetch the page with the requests module but this is unnecessary, since the function is available internally.
Your question is not clear, but as I understand, (1) you think you have to get your form data from one view and send it to another view to do operations. (2) you are not familiar with flask request and flask-wtf. and maybe (3) looking for a way to do this without refreshing or redirecting the page.
You don't need to separate your GET and POST methods. instead you can integrate both in one view.
#app.route('/member/<id>', methods=['GET', 'POST])
To handling data, you can use flask request.
from flask import request
and access to data in your view like this:
id = request.form.get("idField")
but you can also use Flask-WTF to simply make and handle forms.
with Flask-WTF your view would be like this:
from app.forms import SearchForm
#app.route('/your-endpoint', methods=['GET', 'POST'])
def yourView():
form = your_form()
if form.validate_on_submit():
id=form.idField.data
return render_template('test.html', form=form)
the condition form.validate_on_submit() checks if you are submitting a from or you just opened it. if you submit a form and it's data are valid based on validators defined in your form, the code runs. else just renders the template and returns the page.
To learn how to make forms with Flask-WTF I recommend reading this article:
If you don't want to refresh the page or redirect it after submitting the form, you can use AJAx on your page.

User Authentication taking a long time in DRF

I'm using a ModelViewSet with the IsAuthenticatedOrReadOnly permission class, like so:
class PostViewSet(viewsets.ModelViewSet, MarkdownToHTML):
permission_classes = (IsAuthenticatedOrReadOnly,)
When I call this view in the browsable API, the data returns in about 1100 ms (already too long), but when I call it from my frontend UI, the call takes 6000-7000ms!
The only difference between these two methods of calling the same view is that I am passing along a json token from my frontend UI app. When I comment out the token header, the response returns in about 1 second, the same time as in the browsable API.
How could this simple authentication step take over 5 seconds?
Here is the permission class:
class IsAuthenticatedOrReadOnly(BasePermission):
"""
The request is authenticated as a user, or is a read-only request.
"""
def has_permission(self, request, view):
return (
request.method in SAFE_METHODS or
request.user and
request.user.is_authenticated
)
I've run in a similar issue in a project. I would tell you about my experience in order to try to help, I can't tell what is your exact problem but I'll post things I checked when I had mine.
The thing is that decoding the auth token is a very expensive operation, so you have to check:
How many times is such token (if provided) decoded in your view?
Can you use cookies for caching auth token, setting an expire time?
How many time is this token send to and back from the server?
On the other hand, remember DRF will transform you json to a python object (specifically a dictionary) depending on the length of your token (and how many times it occurs) it will be a very expensive operation too.

Django test Client submitting a form with a POST request

How can I submit a POST request with Django test Client, such that I include form data in it?
In particular, I would like to have something like (inspired by How should I write tests for Forms in Django?):
from django.tests import TestCase
class MyTests(TestCase):
def test_forms(self):
response = self.client.post("/my/form/", {'something':'something'})
My endpoint /my/form has some internal logic to deal with 'something'.
The problem was that when trying to later access request.POST.get('something') I couldn't get anything.
I found a solution so I'm sharing below.
The key was to add content_type to the post method of client, and also urlencode the data.
from urllib import urlencode
...
data = urlencode({"something": "something"})
response = self.client.post("/my/form/", data, content_type="application/x-www-form-urlencoded")
Hope this helps someone!
If you are sending dictionaries on old-django versions using client, you must define the content_type='application/json' because its internal transformation fails to process dictionaries, you also need to send the dictionary like a blob using the json.dumps method. In conclusion, the following must work:
import json
from django.tests import TestCase
class MyTests(TestCase):
def test_forms(self):
response = self.client.post("/my/form/", json.dumps({'something':'something'}), content_type='application/json')
If you provide content_type as application/json, the data is serialized using json.dumps() if it’s a dict, list, or tuple. Serialization is performed with DjangoJSONEncoder by default, and can be overridden by providing a json_encoder argument to Client. This serialization also happens for put(), patch(), and delete() requests.
I have tried unit testing the POST requests in Django using Client(), but I fail to make it work (even with the methods specified above). So here is an alternative approach I take exclusively for the POST requests (using HttpRequest()):
from django.http import HttpRequest
from django.tests import TestCase
from . import views
# If a different test directory is being used to store the test files, replace the dot with the app name
class MyTests(TestCase):
def test_forms(self):
request = HttpRequest()
request.method = 'POST'
request.POST['something'] = 'something'
request.META['HTTP_HOST'] = 'localhost'
response = views.view_function_name(request)
self.assertNotIn(b'Form error message', response.content)
# make more assertions, if needed
Replace the view_function_name() with the actual function name. This function sends a POST request to the view being tested with the form-field 'something' and it's corresponding value. The assertion statements would totally depend on the utility of the test functions, however.
Here are some assertions that may be used:
self.assertEquals(response.status_code, 302):
Make this assertion when the form, upon submission of the POST request, redirects (302 is the status code for redirection). Read more about it here.
self.assertNotIn(b'Form error message', response.content):
Replace 'Form error message' with the error message that the form generates when incorrect details are sent through the request. The test would fail if the test data is incorrect (the text is converted to bytes since HttpResponse().content is a bytes object as well).
If the view function uses the Django Message framework for displaying the form error messages as well, include this before the response:
from django.contrib import messages
...
request._messages = messages.storage.default_storage(request)
If the view function uses Sessions, include this before the response:
from importlib import import_module
from django.conf import settings
...
engine = import_module(settings.SESSION_ENGINE)
session_key = None
request.session = engine.SessionStore(session_key)
Before sending out the request, remember the use of any context-processors that your application may use.
I personally find this method more intuitive (and functional). This seems to cover all possible test cases with regard to HTTP requests and forms as well.
I would also like to suggest that each unit test case could be broken down into separate components for increased coverage and discovering latent bugs in code, instead of clubbing all cases in a single test_forms().
This technique was mentioned by Harry J.W. Percival in his book Test-Driven Development with Python.

Acessing POST field data without a form (REST api) using Django

In the django documentation, it says:
HttpRequest.POST
A dictionary-like object containing all given HTTP POST parameters, providing that the request contains form data. See the QueryDict documentation below. If you need to access raw or non-form data posted in the request, access this through the HttpRequest.body attribute instead.
However, the server does not respond to a browser (such as using JS frameworks or a form) but instead a REST api sent by an Anroid/iOS application.
If the client sends fields directly in a POST request, how can I read the data? For example, this (Java + Unirest):
Unirest.post("/path/to/server")
.field("field1", "value2")
.field("field2", "value2");
EDIT: Can I simply read the data usingresponse.POST["field1"], or will I have to do something with request.body?
EDIT 2: So I can simply use request.body as a dictionary-like object similar to request.POST?
As far as I understand the field method from Unirest just uses normal application/x-www-form-urlencoded data like a HTML form. So you should be able to just use response.POST["field1"] like you suggested.
From the docs:
request.data returns the parsed content of the request body. This is
similar to the standard request.POST and request.FILES attributes
except that:
It includes all parsed content, including file and non-file inputs.
It supports parsing the content of HTTP methods other than POST, meaning that you can access the content of PUT and PATCH
requests.
It supports REST framework's flexible request parsing, rather than just supporting form data. For example you can handle incoming
JSON data in the same way that you handle incoming form data.
Can I simply read the data using response.POST["field1"], or will I
have to do something with request.body?
So I can simply use request.body as a dictionary-like object similar
to request.POST?
An example - From a create method (viewsets):
user = dict(
full_name=request.DATA['full_name'],
password=request.DATA['password'],
email=request.DATA['email'],
personal_number=request.DATA['personal_number'],
user_type=request.DATA['user_type'],
profile_id=request.DATA['profile_id'],
account_id=request.DATA['account_id']
)
Edit 1: In version 3 (latest) - request.DATA has been replaced with request.data:
user = dict(
full_name=request.data['full_name'],
password=request.data['password'],
email=request.data['email'],
personal_number=request.data['personal_number'],
user_type=request.data['user_type'],
profile_id=request.data['profile_id'],
account_id=request.data['account_id']
)
If the api you are interacting with is a sipmle Django Class Based view, you access the data through request.body something like this:
class MyView(View):
def post(self, request):
field1 = request.body.get('field1')
field2 = request.body.get('field2')
... # processing here
In case you are using Django rest framework api, you access the data through request.data:
field1 = request.data.get('field1')
field2 = request.data.get('field2')
NB: If you find request.DATA used somewhere in Internet that's correct too, but it's only valid for old version of DRF, and it's deprecated in favor of request.data in the newer versions.

Username available in all templates

I'm trying to make the currently logged in username available in all templates. I can receive it from pyramid.security.authenticated_userid, but to do that I need the request object. I tried to go via the BeforeRender subscription, but as far as I can tell, the request in not passed to that callback.
How else can I make the username available everywhere (or in the base template really)?
A common method is to attach the user object to the request via this cookbook recipe.
Another possibility is to attach it as you suggested using a BeforeRender subscriber. The request is available from the event:
def add_renderer_globals(event):
request, context = event['request'], event['context']
event['user'] = authenticated_userid(request)

Categories

Resources