Understanding request.data in django view - python

I tried looking at different resources on the internet regarding this request and request.data in django, but I couldn't fully understand it.
Why this request parameter is kept inside the function? What are we passing in this request parameter?? Also, what does this request. data do??
def index(request):
content = {
'Blogdata': Blog.objects.all(),
}
return render(request, 'index.html', content)
def somefunction (request):
data=request.data
As you can see I have two functions above both of them have request paramter inside the function. Also, I need the explanation on this request.data as this has to be used multiple times.

First, you should understand about HTTP Request(Header, Body). When you type in form and send to server, browser get data with name and add values into body request. In the backend server, we will get data from body with name.
Example:
I have form fill your name:
<form action="/signin" method="get" name="myForm">
<label for="name">Your name:</label>
<input type="text" id="name" name="name"><br><br>
<input type="button" value="Send form data!">
</form>
You type name : "Khoa", browser get values "Khoa" from input and add key:values with name in . Like this: "name": "Khoa"
In server django, you can get data with using request.data.get("name") = "Khoa"
request.data is body HTTP send to servere, "name" is key part of body have values is "Khoa"

Related

Pass HTML for value to django view (for querying database models)

I have a form input inside my HTML page and want the figure ID that is entered inside the form to be passed into my django view to do a query, displaying info for the figure with the matching ID.
My form:
<form metohd="GET" id="figure_choice_form">
<label for="figure_id">Enter ID</label>
<input type="text" id="figure_id" name="figure_id">
<button> Submit </button>
</form>
My views.py
def from_DB(request):
#request being the ID entered from the form
figures_list = Figure.objects.filter(id=request)
context = {"figures_list":figures_list}
return render(request,"app1/data_from_DB.html",context)
Firstly , Update your html code snippet to correct form attribute "metohd" to "method" .
You are sending data via GET request . So you can access it via request.GET method .
Code snippet of django view.
def from_DB(request):
id = request.GET.get("figure_id")
figures_list = Figure.objects.filter(id=id)
context = {"figures_list":figures_list}
return render(request,"app1/data_from_DB.html",context)
This does your required work .

FLask : submitting different actions with a dynamically generated form

I am building a basic Flask application with a sqlite database.
The feature I am having trouble implementing is for a user to be able to accept or refuse a contact request (like a friend request) from another user.
On the "/contacts" page, you can see all the contact requests you received from other users without problem, but I want to add the option to accept or refuse them and this is where I'm stuck.
A form is dynamically generated by fetching from the database all the contact requests the current user has received and displaying them on the page.
I have tried using two <input type="submit" name="accept/delete" value="id_of_the_request"> tags for each requests, one with the accept option, the other with the delete option, both leading to the same route, but unlike some other input types, the "value" property controls what text appears on the button, so I can't set that to, say, the id of the contact request (which I did in the code further below) because then I see two buttons with a number on my page.
I thought about doing the opposite and setting the name of the tag to the request's id instead, and the value to "delete" or "accept", but then on the server side I wouldn't know what name to get with request.form.get() since the request's id are dynamically generated in the form depending on what's in the database.
I feel like I'm missing some basic knowledge and that it shouldn't be too hard to do that though.
Here is my html code (the template is passed a list of dictionaries (requests) from the database, corresponding to the list of contact requests received by the current user. Each request consists of 3 columns : request_id, user_email, contact_email. request_id is the primary key, user_email is the email of the person who sent the request, while contact_email is the email of the person who received it. ):
<form action="/manage_requests" method="post">
<ul>
{% for request in requests %}
<li>{{request.user_email}} sent you a contact request.</li>
<input type="submit" name="accept" value="{{request.r_id}}">
<input type="submit" name="refuse" value="{{request.r_id}}">
{% endfor %}
</ul>
</form>
Here is my python code to handle accepting or refusing the request :
#app.route("/manage_requests", methods = ["POST"])
#login_required
def manage_requests():
acceptedID = int(request.form.get("accept"))
refusedID = int(request.form.get("refuse"))
## Add the user who sent the request as a contact for both them and us, then delete the request.
if acceptedID :
# fetch the info of the request corresponding id from the database requests table
# get the sender's user_email
# insert the data into the database contacts table for both the sender and the receiver (current user)
# delete the request from the requests table in the database
return redirect("/contacts")
## Delete the request
elif refusedID :
# delete the request from the database requests table
return redirect("/contacts")
This is how I would have done it:
First a route that returns all contact requests like you did:
#app.route("/contacts", methods = ["POST"])
#login_required
def contacts():
# requests_list = Find all the requests for a user
return render_template('contacts.html', requests_list=requests_list)
Then I return in my template all the requests found:
<ul>
{% for request in requests %}
<li>{{request.user_email}} sent you a contact request.</li>
<a href="{{ url_for('manage_requests', request_id=request.r_id, action='accept' )}}">
<input type="submit" name="accept">
</a>
<a href="{{ url_for('manage_requests', request_id=request.r_id, action='refuse' )}}">
<input type="submit" name="refuse">
</a>
{% endfor %}
</ul>
Note how I use the <a></a> tag around the submit button, with the Jinja2 url_for function passed to the href attribute, with the request_id as a parameter and a variable action which takes as the value either accept or refuse:
And finally:
#app.route("/manage_requests", methods = ["POST"])
#login_required
def manage_requests():
action = request.args.get('action')
request_id = int(request.args.get('request_id'))
## Add the user who sent the request as a contact for both them and us, then delete the request.
if action == "accept" :
# fetch the info of the request corresponding id from the database requests table
# get the sender's user_email
# insert the data into the database contacts table for both the sender and the receiver (current user)
# delete the request from the requests table in the database
return redirect("/contacts")
## Delete the request
else :
# delete the request from the database requests table
return redirect("/contacts")

Why BadrequestKeyError is showing?

I am making a small project - Reminider System. I have a form which accepts values from users and inserts into the database table. The problem is occurring while fetching a value from a textbox. Below is my code and also I am giving what error am getting.
<form method="POST" action="">
<input type="hidden" name="unique" value="{{session.UID}}" disabled="true">
<button type="submit" class="btn btn-primary">Confirm</button>
</form>
This is my template
#app.route('/home/set_reminder',methods=['POST'])
#is_logged_in
def set_reminder():
if request.method=='POST' and form.validate():
uid = request.form['unique']
I am getting the error in this line uid = request.form['unique']. Not getting why it cannot fetch the value.
werkzeug.exceptions.BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'unique'
And this is the error which am getting.
Please help me out.
In your html, the uid input is disabled, so the browser will not send uid in a POST request's body. This causes the error when you try to access request.form.uid - it doesn't exist.
You could use readonly rather than disabled if the value must be returned by the browser.
See this answer for a little more information on BadRequestKeyError.

When handling a form POST in a Django views.py, it appears to ignore the HttpResponse type

I have a Django application that generates a table of data. I have a form where you enter parameters and click one button to see the results or another to download a CSV. Seeing the results is working, but downloading the CSV is not.
I handle the response in the views.py, set the content type and disposition, and return the response. Rather than downloading the CSV, it displays the data as text. (I tried both StreamingHttpResponse and plain HttpResponse.) The same exact code works when handling a URL passing in the parameters. So, I tried a HttpResponseRedirect instead, and it does nothing. I even tried just redirecting to a plain URL, with no effect. I believe the response type is being ignored, but I don't know why.
html:
<form action="" method="post" class="form" id="form1">
{{ form.days }} {{ form.bgguserid }}
<input type="submit" value="Go!" id="button-blue"/>
<input type="submit" name="csv-button" value="CSV" id="csv-button"/>
</form>
views.py attempt 1:
def listgames(request, bgguserid, days=360):
if 'csv-button' in request.POST:
# create CSV in variable wb
response = StreamingHttpResponse(wb, content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename="collectionvalue.csv"'
return response
attempt 2, the same but with:
response = HttpResponseRedirect ('/collection/{0}/csv/{1}/'.format(bgguserid,days))
I'm open to other solutions like a client-side redirect to the functioning URL, but I don't want to lose the form validation, and my HTML/javascript skills are weak.
I figured out the problem.
The code in views.py (which I partly copied from somewhere) was creating a new HttpRequest object from the return value of the form handling method.
def indexform(request):
if request.method == 'POST':
form = IndexForm(request.POST)
# Check if the form is valid:
if form.is_valid():
# process the data in form.cleaned_data as required
response = listgames(request, bgguserid=form.cleaned_data['bgguserid'], days=form.cleaned_data['days'])
# redirect to a new URL:
return HttpRequest(response)
By changing that last line to just return response, it works as intended. Sorry for wasting anyone's time.

Proper Accessor for Django Uploaded Files

Assuming a Django form like the following...
class MyForm(forms.Form):
attachment = forms.FileField()
I've seen many tutorials which access uploaded Django files with request.FILES['attachment'], however I was under the impression that whenever possible you should access POSTed data via form.cleaned_data['attachment'].
Is there a reason why one would use request.FILES[]? Should these objects contain the exact same data?
When you create a form in HTML, it has a particular encoding (or method of sending the data to the server). By default, the encoding is application/x-www-form-urlencoded, which essentially sends the form details in a single string. However, if you want to upload files to the server, you need to set the encoding to multipart/form-data (thats the enctype="..." line you'll notice in all tutorials on the subject). This sends the data in multiple parts, one per form field. For an example of how the two encodings appear, see here.
When Django encounters the multipart/form-data encoding, it splits the received data into two dictionaries: the request.FILES dictionary contains any files uploaded, while request.POST contains any other form fields. If you are interested, the processing is done by the MultiPartParser class in the django/http/__init__.py file.
To illustrate how this data is presented back to your code, lets create a simple application. First, lets make a simple form consisting of a character field and a file field:
from django import forms
class TestForm(forms.Form):
name = forms.CharField()
file = forms.FileField()
Next, we'll create a simple view to create a form, bind any submitted data to it, and render it through a template:
from django.shortcuts import render_to_response
from django.template import RequestContext
from forms import TestForm
def show_form(request):
if request.method == 'POST':
form = TestForm(request.POST, request.FILES)
else:
form = TestForm()
context = {
'form': form
}
return render_to_response('show_form.html', context, RequestContext(request))
And finally, we'll use the template to display the form and some information about both the request and the form:
<html>
<head>
<title>Django forms - file test</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" />
</form>
<h2>Request details</h2>
<p>
Request method: {{ request.method }}
<br />
POST data: {{ request.POST|default:"No data" }}
<br />
FILES data: {{ request.FILES|default:"No data" }}
</p>
<h2>Form details</h2>
<p>
Cleaned data: {{ form.cleaned_data|default:"No data" }}
</p>
</body>
</html>
Note that you'll need to enable the django.core.context_processors.request context processor in your settings to see the details about the request.
If we then fire up the server and point our browser to the view, we see what we'd expect to see - an empty form, the request mode was GET, and there was no POST, FILES or form data.
Next, enter a name in the character field but don't pick a file to upload. Upon submitting, we get the expected error about the file field being required. Of more interest to us is the information about the request:
Request details
Request method: POST
POST data: <QueryDict: {u'csrfmiddlewaretoken': [u'b032358a4dbd71bc3a776c2ef41b09d9'], u'name': [u'Blair'], u'file': [u'']}>
FILES data: No data
Form details
Cleaned data: No data
As there was no file information sent by the browser, Django has put all the form details into the POST dictionary and left the FILES dictionary empty. As the form is invalid, there is no data associated with it.
Now lets try it without a name, but with a file to upload:
Request details
Request method: POST
POST data: <QueryDict: {u'csrfmiddlewaretoken': [u'b032358a4dbd71bc3a776c2ef41b09d9'], u'name': [u'']}>
FILES data: <MultiValueDict: {u'file': [<InMemoryUploadedFile: image.pdf (application/pdf)>]}>
Form details
Cleaned data: No data
Now, the submitted data has been split between the POST and FILES dictionaries. The file can be accessed through request.FILES['file'], but not through the forms cleaned data, as the form was invalidated by the lack of a name. As the file I uploaded was small, it is stored in memory; files above a certain size (2.5MB by default) would be stored in a temporary directory, but your code can handle them the same.
Finally, lets try it with values for both fields:
Request details
Request method: POST
POST data: <QueryDict: {u'csrfmiddlewaretoken': [u'b032358a4dbd71bc3a776c2ef41b09d9'], u'name': [u'Blair']}>
FILES data: <MultiValueDict: {u'file': [<InMemoryUploadedFile: image.pdf (application/pdf)>]}>
Form details
Cleaned data: {'name': u'Blair', 'file': <InMemoryUploadedFile: image.pdf (application/pdf)>}
As the data is valid and bound to the form, the file can also be accessed through the cleaned_data of the form.
There is a potential benefit through accessing it through request.FILES: if the form is invalid, you can still save the file somewhere before asking the user to correct the data. This prevents having to upload the file again (which could be quite costly in terms of time and bandwidth if you are dealing with large files). If you only want to work with small files, it won't make much difference, but it is probably better practice to use request.FILES. This is also how the Django file upload documentation does it.

Categories