I am trying to understand an issue with Google App Engine and Python. It appears that I cannot have a POST handler in the MainPage class. Or, I am somehow using it incorrectly. The system does not object to the Python code but does not seem to find the post method. The response from the server is "405 Method Not Allowed" and "The method POST is not allowed for this resource. "
The output on the dev_appserver.py console is
INFO 2018-11-14 13:41:32,104 module.py:861] default: "GET / HTTP/1.1" 200 267
INFO 2018-11-14 13:41:35,550 module.py:861] default: "POST / HTTP/1.1" 405 188
The original source is
# -*- coding: utf-8 -*-
import webapp2
import logging
form = """
<form action="/" method="post">
<input type="checkbox" name="vehicle" value="Bike">Bike<br>
<input type="checkbox" name="vehicle" value="Car">Car<br>
<input type="submit" value="Submit" >
</form>
"""
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.write(form) # write the blank form
def post(self):
logging.info("in MainPage>post")
self.response.write("Thanks! That works !!!")
app = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
The GET method is invoked correctly and the simple form is displayed properly. The 405 error appears when I make a selection and submit the form. I have declared the form with both;
<form action="/" method="post">
and
<form method="post">
I can create an additional class that can contains a POST method and have action select the other class; everything works fine. I just have not found any logical reason it cannot correctly function in MainPage.
Related
I have the code below in my Python script:
def cmd_wui(argv, path_to_tx):
"""Run a web UI."""
from flask import Flask, flash, jsonify, render_template, request
import webbrowser
app = Flask(__name__)
#app.route('/tx/index/')
def index():
"""Load start page where you select your project folder
or load history projects from local DB."""
from txclib import get_version
txc_version = get_version()
prj = project.Project(path_to_tx)
# Let's create a resource list from our config file
res_list = []
prev_proj = ''
for idx, res in enumerate(prj.get_resource_list()):
hostname = prj.get_resource_host(res)
username, password = prj.getset_host_credentials(hostname)
return render_template('init.html', txc_version=txc_version, username=username)
Also, I have an HTML form in init.html:
<form>
<input type="text" id="projectFilepath" size="40" placeholder="Spot your project files">
<input type="button" id="spotButton" value="Spot">
</form>
How can I pass the user input from "projectFilepath" when a user clicks "spotButton" on a variable in my python script?
I'm new in Python and Flask, so forgive me if I make any mistakes.
The form tag needs some attributes set:
action: The URL that the form data is sent to on submit. Generate it with url_for. It can be omitted if the same URL handles showing the form and processing the data.
method="post": Submits the data as form data with the POST method. If not given, or explicitly set to get, the data is submitted in the query string (request.args) with the GET method instead.
enctype="multipart/form-data": When the form contains file inputs, it must have this encoding set, otherwise the files will not be uploaded and Flask won't see them.
The input tag needs a name parameter.
Add a view to handle the submitted data, which is in request.form under the same key as the input's name. Any file inputs will be in request.files.
#app.route('/handle_data', methods=['POST'])
def handle_data():
projectpath = request.form['projectFilepath']
# your code
# return a response
Set the form's action to that view's URL using url_for:
<form action="{{ url_for('handle_data') }}" method="post">
<input type="text" name="projectFilepath">
<input type="submit">
</form>
You need a Flask view that will receive POST data and an HTML form that will send it.
from flask import request
#app.route('/addRegion', methods=['POST'])
def addRegion():
...
return (request.form['projectFilePath'])
<form action="{{ url_for('addRegion') }}" method="post">
Project file path: <input type="text" name="projectFilePath"><br>
<input type="submit" value="Submit">
</form>
I'm using Django 3.2b1 and pytest 6.2.2.
I'm trying to use pytest to write a test to make sure admins are able to delete objects using the delete_selected action. My test looks like this:
def test_delete_mymodel_action(admin_client):
objs_to_delete = [
MyModel.objects.create(),
MyModel.objects.create(),
]
MyModel.objects.create() # Don't delete this obj
data = {
"action": "delete_selected",
"_selected_action": [str(f.pk) for f in objs_to_delete],
"post": "yes", # Skip the confirmation page
}
change_url = reverse("admin:myapp_mymodel_changelist")
admin_client.post(change_url, data)
assert MyModel.objects.count() == 1
The code works and ends in a 302 redirect back to the changelist, but the objects don't get deleted. The response is:
test_delete_mymodel_action - assert 3 == 1
The reason I'm testing this is that certain code can cause the delete_selected action to fail. For example, if you override get_queryset() in the ModelAdmin and return a queryset that uses distinct(), the delete_selected action will fail.
Here the code from a delete confirmation page in Django Admin:
<form method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="VCR7vjVYcb2xuMdPUknotrealViwj92wgZrT21k6RbqGxXNlQnCORU1Fp6NzKhn64">
<div>
<input type="hidden" name="_selected_action" value="31418">
<input type="hidden" name="_selected_action" value="31412">
<input type="hidden" name="action" value="delete_selected">
<input type="hidden" name="post" value="yes">
<input type="submit" value="Yes, I’m sure">
No, take me back
</div>
</form>
Some helpful references:
Django's delete_selected() method.
Testing custom admin actions in django SO Answer
I just run into the same problem. I noticed I was logged in with the wrong user.
My thought process:
302 doesn't indicate there's anything wrong, there was no content in the response either (b'')
I added follow=True to self.client.post. The response was 200 and there were no objects, so I assumed it worked correctly but it failed on assertion
I put breakpoint in delete_selected of django.contrib.admin.actions and n = queryset.count() was 0.
If it's not listed after but there's nothing to delete (n = 0), let's see if there was something to be deleted before.
response = self.client.get(reverse("admin:myapp_mymodel_changelist"))
self.assertContains(response, obj.id)
nope!
So the problem with your test is that these objects can't be deleted because they can't be retrieved, probably due to some filtering.
Note, Django admin won't raise 404 if the object has not been found.
I am new to scrapy and in general web tech.
While working on a scrapy example to perform auto login. I came across 1 field , referrer url . I am wondering when do i need to this.
return scrapy.FormRequest.from_response(
response,
url='www.myreferrer.com', #when do i need this ???
formnumber=1,
formdata=self.data['formdata'],
callback=self.after_login
)
I tested with and without it and it works in both instances.
I understand that referrer url is for security but how do i determine from html code that i need or dont need this ?
ADDON
The following html form required the url to be defined :
<form id="login" enctype="multipart/form-data" method="post" action="https:///myshop.com/login/index.php?route=account/login">
I am a returning customer.<br>
<br>
<b>E-Mail Address:</b><br>
<input type="text" name="email">
<br>
<br>
<b>Password:</b><br>
<input type="password" name="password">
<br>
Forgotten Password<br>
<div style="text-align: right;"><a class="button" onclick="$('#login').submit();"><span>Login</span></a></div>
</form>`
class FormRequest(Request):
# delete some code here
#classmethod
def from_response(cls, response, formname=None, formid=None, formnumber=0, formdata=None,
clickdata=None, dont_click=False, formxpath=None, formcss=None, **kwargs):
url = _get_form_url(form, kwargs.pop('url', None))
def _get_form_url(form, url):
if url is None:
return urljoin(form.base_url, form.action)
return urljoin(form.base_url, url)
if the url is empty, it uses form tag's action attribute to get the URL.
if the url is not empty, then it use the URL you give to it.
the base_url comes from the response.
def _get_form(response, formname, formid, formnumber, formxpath):
"""Find the form element """
root = create_root_node(response.text, lxml.html.HTMLParser,
base_url=get_base_url(response))
so, when the action attribute does not exist or the login requests is not sent to the action URL, you need to pass the argument.
I am using cherrypy to run an interactive website and although the python function to generate the CSV seems to be working (if you interact with it directly, my browser downloads it), it does not seem to be giving the user this CSV file when I embed it in a form request:
<form id="export_csv_left" action="/c/flex_export_csv" method="get">
<input type="hidden" name="datakey" value="8TZbmRZ54IL7" >
<button type="button">Export stories and data as CSV</button>
</form>
I'd like there to be a button that says "export CSV" and return the file.
That form generates a request to my cherrypy that looks like this:
djotjog.com/c/flex_export_csv?datakey=8TZbmRZ54IL7
The headers inside the cherrypy part are...
csv = make_csv(literal_eval(raw_data), filename)
cherrypy.response.headers['Content-Type'] = "application/x-download"
cherrypy.response.headers['Content-Disposition'] = ('attachment; filename= %s' % (filename,))
return csv
And loading that link in the browser DOES generate the CSV. So what's up with the form stuff?
Here are some potentially relevant javascript console messages I don't really understand:
Denying load of chrome-extension://ganlifbpkcplnldliibcbegplfmcfigp/scripts/vendor/jquery/jquery.min.map. Resources must be listed in the web_accessible_resources manifest key in order to be loaded by pages outside the extension.
In case that's related.
Your issue has nothing to do with CherryPy per se. Just make sure your form button type attribute is submit and response content-type header is generic application/octet-stream (or text/csv). Like this.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 4
}
}
class App:
#cherrypy.expose
def index(self):
return '''<!DOCTYPE html>
<html>
<body>
<form action="/gimmefile" method="get">
<input type="hidden" name="key" value="8TZbmRZ54IL7"/>
<button type="submit">Export CSV</button>
</form>
</body>
</html>
'''
#cherrypy.expose
def gimmefile(self, key):
cherrypy.response.headers['Content-Type'] = 'application/octet-stream'
cherrypy.response.headers['Content-Disposition'] = 'attachment; filename=yourfile.csv'
return 'Your;file;content;and;{0}'.format(key)
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
I am attempting a fairly simple form on Django 1.3, and am trying to understand how CSRF works.
I think I've followed the three steps detailed on the Django site, but am still unable to make the form work.
The form displays when the URL is loaded, however upon hitting the submit button, I get the following error:
TypeError at /txt/ txt() takes exactly
1 argument (2 given)
Here's the actual code:
views.py:
from django.http import HttpResponse
from django.shortcuts import render_to_response, redirect
from django.template import RequestContext
def txt(request):
if request.method == 'POST':
msg="txt received"
else:
msg="nothing in POST"
return render_to_response('base.html', locals(), context_instance=RequestContext(request))
The HTML:
<body>
<form action="txt/" method="POST">{% csrf_token %}
From <input type="text" name="From"><br>
To <input type="text" name="To"><br>
Body <input type="text" name="Body"><br>
<input type="submit" value="Search">
</form>
{{ msg }}
</body>
I know I haven't done a forms.py etc. but I was just trying to get the basic functionality up and going. I think this code would have worked in previous versions of Django, and am unsure why its not working this time.
The error looks like your view function is getting more arguments than it is setup to accept. As you have it shown above, the view only accepts a single argument: the request.
If your URL pattern for this view is configured with a capturing group, or you are adding extra arguments via the optional dictionary or the kwargs parameter to url(), then those extra arguments will be given to the view function and could cause the error you're seeing.