Flask Bad Request Error; ocurring because of multiple POST requests [duplicate] - python

This question already has answers here:
Why dict.get(key) instead of dict[key]?
(14 answers)
Closed 4 years ago.
<form method = "POST">
<div class=" col-lg-4 col-lg-4 col-lg-4 col-lg-4">
<div class="box">
<input type="text" name="image-url" placeholder="Image URL Link"style="color:black" required="required" value = "new"/>
<textarea cols=80 rows=4 style="color:black" name = "description" placeholder="Place your description here" value = "new"></textarea>
<button type="submit">Upload</button>
</div>
</div>
</form>
{% for i in range(amount_of_images) %}
<div class=" col-lg-4 col-lg-4 col-lg-4 col-lg-4">
<div class="box">
<img src="{{image[i]}}" alt="view" width = "300" height = "300"/>
<form method = "POST">
<textarea cols=80 rows=4 style="color:black" name = "update-description" value = "update">{{description[i]}}</textarea>
<button type="submit">Update Description</button>
</form>
Above is my HTML/Jinja Code
#app.route("/gallery-manager", methods = ["GET", "POST"])
def gallery_manager():
if request.method == "POST":
if(request.form["image-url"] and request.form["description"]) is not None:
model.add_new_image(request.form["image-url"], request.form["description"])
id, image, description, amount_of_images = model.get_gallery()
return render_template("gallery-manager.html", image = image, description = description, amount_of_images = amount_of_images, id = id)
if request.form['update-description'] is not None:
print("hello")
id, image, description, amount_of_images = model.get_gallery()
return render_template("gallery-manager.html", image = image, description = description, amount_of_images = amount_of_images, id = id)
Above is my Python/Flask Code...
The issue, when I click on the update-description submit button, aka the second POST being handled in the html code, I get a 400 error
Bad Request
The browser (or proxy) sent a request that this server could not understand.
I realized that this error occurs when one of the POST fields are empty and can not be found. I understand that this happens because when I click the second POST submit button, it runs through the first POST check (request.form["image-url"] etc and finds that it is satisfied therefore wanting to run that code, but cant because update-description is still empty. How do I avoid this.
In other words how do I handle multiple POST methods.
Thank you,

This is because you are missing the action section in form where the form should send the request
<form action="/whereYouWantToSendRequest" method="post">
add your url endpoint by replacing this in the above
whereYouWantToSendRequest
here are the two request
<input type="text" name="image-url" value = "new"/>
<input type="text" name="update-description" value = "update"/>
and to figure out which request
if request.form["image-url"] == "new":
somethinggg
elif request.form["update-description"] =="update":
sommmm

Related

Flask JWT-extended not recognizing access token, only when GET method is used

Hi everyone!
I'm building a website, and I'm stuck with sending a form. My problem is that it sends the access_token_cookie, but triggers the unauthorized_token_callback. I saw the request and the respone and the request contains the token, but the code pretends like it's not even there.
I can't wrap my head around it, and I need some good tips.
Here is the JWT configuration, the secret keys are not included in this snippet:
application.config['JWT_TOKEN_LOCATION'] = ['cookies', 'headers', 'json', 'query_string']
application.config['JWT_COOKIE_SECURE'] = False #! Needs to be changed in production
application.config['JWT_COOKIE_CSRF_PROTECT'] = True
application.config['JWT_CSRF_CHECK_FORM'] = True
application.config['JWT_COOKIE_SAMESITE'] = 'Strict'
application.config['CSRF_COOKIE_NAME'] = 'csrf_token'
application.config['JWT_ACCESS_CSRF_HEADER_NAME'] = ['X-CSRF-TOKEN-ACCESS', 'X-CSRFToken']
application.config['JWT_CSRF_IN_COOKIES'] = True
I'm using a custom decorator, that restricts the user access based on the role of the user:
def Xrole_required(fn):
#wraps(fn)
def wrapper(*args, **kwargs):
verify_jwt_in_request()
role = dth.get_user_by_email(get_jwt_identity()).roles.role_name
if(role != 'required_role'):
flash('Xrole required', 'error')
return Response(render_template('404.html', title='Not Logged In'), 404, mimetype='text/html')
else:
return fn(*args, **kwargs)
return wrapper
Whenever I remove the decorator, it redirects me with no problem, but using it says that I'm not logged in. I use this decorator on other places and there it works perfectly fine.
The interesting thing is, that this works on every GET request, but it does not, on other methods. Here is the form, so you can see it:
<form class="form-control" action="{{ url_for('MyEndpoint_name', show='active') }}" method="POST">
<div class="row pt-2">
<label for="desc" class="required">Description</label>
<input id="desc" name="desc" type="text" required class="shadow-sm rounded border">
</div>
<div class="row pt-2">
<label>Text</label>
<input type="text" class="shadow-sm rounded border">
</div>
<div class="row pt-2">
<label>Number</label>
<input type='number' value="0" min="0" class="shadow-sm rounded border">
</div>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
And here is the resource that handles the request:
class MyResource(Resource):
#Xrole_required
def post(self, show):
#here comes the code, this is only for test
return redirect(url_for('/redirect_page'), 303)
Did I make a mistake in here somewhere, or did I miss some crucial part of the documentation?
Please note, that I don't want to use XMLHttpRequest, because it would be an overkill, I have a lot of js already and these are simple forms.
You are probably running into a CSRF problem. Make sure to set JWT_CSRF_CHECK_FORM to True and include the CRSF token in a hidden field in your form by using https://flask-jwt-extended.readthedocs.io/en/stable/api/#flask_jwt_extended.get_csrf_token

Django how to update a template without refreshing/redirecting?

I'm trying to make a simple commenting system where someone can add their comment to a post and it'll show up without having to redirect them or refresh the page. This is what my code basically looks like:
def post_details(request):
details = {}
if request.method == "POST":
request.POST
# Function here for creating a new comment
details['new_comment'] = new_comment
details['post_details'] = post_details
else:
details['post_details'] = post
return render(request, 'post_details.html', details)
The post_details.html shows a post with comments below it along with a form that adds their comment. I tried to add a new block of code in the template file for new_comment and the issue is that when I add a new comment, it will update that part but adding another one won't show up.
I should also note that I have CSV files that store the post and comment details. In my models.py file, I have my classes and methods to read in the CSV files so the function I left out does update the file with the comments. I'm trying to do this without Javascript but I'm open to trying anything, just really want to solidify my understanding of requests. I hope this wasn't confusing.
You can use JavaScript (AJAX) in this situation.
Create a base division in your template for showing your comments.
Then create an input form field for user to write comment.
Give the submit button id such as "addcomment" in my case.
Create the below ajax function with proper input values.
AJAX Function in JAVASCRIPT
$('#addcomment').click(function(){
// Taking_username_from_input_field_with_id_username.
var user = $('#username').val();
var usercomment = $('#usercomment').val(); // Taking_comment_from input_field_with_id_usercomment.
var csr = "{{csrf_token}}"; // Creating CSRF Token
$.ajax({
url: "{% url 'savecomment' blog.blog_id %}",
method:"POST",
data:{
user:user,
usercomment:usercomment,
csrfmiddlewaretoken:csr
},
success:function(data){
form.reset(); // resetting form values.
var output = "";
output =` <div class="comment">
<div class="comment-header d-flex justify-content-between">
<div class="user d-flex align-items-center">
<div class="image"><i class="fa fa-arrow-right"></i></div>
<div class="title"><strong>${data.user}</strong><span class="date">${data.date}</span></div>
</div>
</div>
<div class="comment-body">
<p>${data.comment}</p>
</div>
</div>`
$('.post-comments').append(output); // Appending data_in existing values which loaded_in first run.
//for_updating commentcount
var commentcount = data.number_of_comments;
$('.no-of-comments').replaceWith(`<span class="no-of-comments">(${commentcount})</span>`);
}
});
COMMENTS TEMPLATE
<div class="post-comments">
<header>
<h3 class="h6">Post Comments<span class="no-of-comments">0</span></h3>
</header>
</div>
FORM TEMPLATE
<form id="form" action="#" class="commenting-form">
<div class="row">
<div class="form-group col-md-6">
<input type="text" name="username" value="{{page.username}}" id="username" placeholder="Name"
class="form-control" disabled>
</div>
<div class="form-group col-md-12">
<textarea name="usercomment" id="usercomment" placeholder="Type your comment"
class="form-control"></textarea>
</div>
<div class="form-group col-md-12">
<button id="addcomment" type="button" class="btn btn-secondary">Submit Comment</button>
</div>
</div>
</form>

Load data based on user inputs

I am working with dynamic data that requires an ID and a year to load, both of which are input by the user. The ID is unique, so two users will very likely be looking at different data. They are passed into a URL that returns a large dictionary. This dictionary is then passed to a bunch of other functions for various analyses and visuals. I was thinking of displaying the data in its own hidden route and have other routes call on it (I am new to flask, so there could be a better/more efficient way of storing and accessing dynamic data like this).
Here is the flask code to display the form and where I try to access the data:
#app.route("/")
def home():
return render_template("index.html")
#app.route("/data/<lid>/<ssn>", methods=["GET","POST"])
def data_league():
if request.method == "POST":
league_id = request.form["lid"]
season = request.form["ssn"]
url = 'http://fantasy.espn.com/apis/v3/games/ffl/seasons/' + season + '/segments/0/leagues/' + league_id + '?view=mMatchupScore&view=mTeam&view=mSettings'
r = requests.get(url,
params={'view':'mMatchup'})
d = r.json()
return d
And the HTML code that creates the form:
<form class="row row-cols-lg-auto g-3 align-items-center" action="#" method="post" style="margin-
left: 180px;">
<div class="col-5">
<label class="visually-hidden" for="league_id">Username</label>
<div class="input-group">
<input type="text" class="form-control" name="lid" id="lId" placeholder="League ID">
</div>
</div>
<div class="col-5">
<label class="visually-hidden" for="season">Preference</label>
<select class="form-select" name="ssn" id="Ssn">
<option selected>Select a Season</option>
<option value="1">2020</option>
<option value="2">2019</option>
<option value="3">2018</option>
</select>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
When I run the app and input an ID and year, I get a TypeError saying that "data_league() got an unexpected keyword argument 'lid'". What am I doing wrong?

How to return the value of a "datetime-local" input type from HTML to python flask in strings

The purpose of this piece of code is to ask users to input a specific date and time. The input should be sent from the HTML form to app.py, and the python script should check the input and display "available stalls" accordingly.
I tried this:
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Please select a date & time to view available stalls : </h3>
</div>
<div class="box-body">
<form method="POST" action="">
<div class="form-group">
<label>Date and time range:</label>
<div class="input-group">
*****<input type="datetime-local" id="reservationtime"
name="reservationtime" value="2019-11-15T14:30"
min="2019-01-01T00:00" max="2030-12-31T00:00">*****
</div>
<button type = "submit" class="btn btn-primary">Submit</button>
<!-- /.input group -->
</div>
</form>
</div>
</div>
</div>
</div>
the python code is:
resultstruct_time = time.strptime(reservationtime,"%Y-%m-%d %H:%M")
reservationDayID = resultstruct_time(6) + 1
reservationHour = resultstruct_time(3)
And the error I have been getting is:
TypeError: strptime() argument 0 must be str, not class 'NoneType'
Could anyone help me solve this problem by telling me how to change the input into str while keeping the input type as "datetime-local?" Thank you!
Edit: It seems that the HTML form is returning nothing to python. But why does that happen? Is there any way to pass back the desired value of "reservationtime?" Here's a repost of all the relevant code down below:
python:
#app.route("/FilterStallsPage",methods = ["GET","POST"])
def DisplayFilterStallsPage():
stallsInfoDict, availableStallsCount = filterAvailableStalls()
return render_template('FilterStallsPage.html',stallsInfoDict = stallsInfoDict, \
totalStalls = len(stallsInfoDict), availableStalls = availableStallsCount)
def getReservationTime():
if request.method == "POST":
reservationtime = request.form["reservationtime"]
return reservationtime
def filterAvailableStalls():
reservationtime = getReservationTime()
resultstruct_time = time.strptime(str(reservationtime),"%Y-%m-%d %H:%M")
reservationDayID = resultstruct_time(6) + 1
reservationHour = resultstruct_time(3)
(the rest block of irrelevant code not included)
HTML:
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Please select a date & time to view available stalls : </h3>
</div>
<div class="box-body">
<form method="POST" action="">
<div class="form-group">
<label>Date and time range:</label>
<div class="input-group">
*****<input type="datetime-local" id="reservationtime"
name="reservationtime" value="2019-11-15T14:30"
min="2019-01-01T00:00" max="2030-12-31T00:00">*****
</div>
<button type = "submit" class="btn btn-primary">Submit</button>
<!-- /.input group -->
</div>
</form>
</div>
</div>
</div>
</div>
Thank you!
I'm guessing nothing is being returned. You could try adding print at the place where the python receives the response. Print type of the response received then start debugging from there. Try type casting to string. Try checking if nothing is returned. Sometimes nothing is returned and its a noneType object.
print(type(reservationtime) ) #debugging
print(reservationtime) #debugging
resultstruct_time = time.strptime(str(reservationtime),"%Y-%m-%d %H:%M")
edit-helping-debug
def getReservationTime():
if request.method == "POST":
print('made to POST')
return "test-string"
#reservationtime = request.form["reservationtime"]
#return reservationtime
okay if you get the print and it doesn't return a noneType it means you only have to fix the commented lines.
If it doesn't make it there you have to fix the get reservation code that handles generating the post. I haven't worked with flask enough to give you the exact answer just keep fiddling with it and see wether a post request is even occurring.

Python : How to submit CGI form using Request

I just start learning Python and want to make a script to submit Form.
I found Form use CGI, Here the Form:
<div class="box" id="url_upload">
<div class="tabcontent">
<div class="progress_div"></div>
<div class="reurlupload">
<div class="progress_div"></div>
<form method="post" id="uploadurl" action="https://af03.ayefiles.com/cgi-bin/upload.cgi?upload_type=url">
<input type="hidden" name="sess_id" value="xv71zsrmtr38oh3z">
<input type="hidden" name="utype" value="reg">
<input type="hidden" name="file_public" value="1">
<div class="leftintab">
<p style="margin:0px;">
You can enter up to <b>20</b> URLs, one URL per row</br>
Max file size is <b>10240 Mb</b>
</p>
<textarea name="url_mass" style="width:100%; margin-top: 10px;" placeholder="e.g. http://example.com/xxxxxxxxxx.xyz"></textarea>
</div>
I make python script using request as below:
#I have session with my login & password as cookie
#Go to form page
login = s.get('https://ayefiles.com/?op=upload_form')
login_html = html.fromstring(login.content)
hidden_inputs = login_html.xpath('//input[#type="hidden"]')
# Input query data
form = {x.attrib["name"]: x.attrib["value"] for x in hidden_inputs}
form ['sess_id']= 'xv71zsrmtr38oh3z'
form['utype']= 'reg'
form ['file_public']= '1'
form['url_mass'] = longurl
# POST
login = s.post('https://af03.ayefiles.com/cgi-bin/upload.cgi?upload_type=url', data=form)
print (login.url)
My expected result for login.url ==> ayefiles.com/?op=upload_result&st=OK&fn=xxxxx
But my result fail, ==> ayefiles.com/?op=upload_result&st=Torrent%20engine%20is%20not%20running&
fn=undef
how to solve my problem? What's wrong with my code?
Please kindly help me with correct code.
My mistake at part multiform data.
Correct code :
form ={'sess_id':(None,'xv71zsrmtr38oh3z'),'utype':(None,'reg'),'file_public':(None,'1'),'url_mass':(None,longurl)}
login = s.post('https://af03.ayefiles.com/cgi-bin/upload.cgi?upload_type=url', data=form)

Categories

Resources