Python Flask routes conflict - flask

I am using python flask for a web application and I have following routes in my python file
#app.route("/admin", methods=['GET', 'POST'])
def admin():
print "In admin method. With request method: ", request.method
pass
#app.route("/<query>", methods=['GET'])
def search(query):
print "In search method. With request method: ", request.method
pass
My app is doing something very weird. I added print statements to know where the request goes through and in my admin.html file when I submit the form that looks like below
<script type="text/javascript">
$(document).ready(function() {
$('.form-horizontal').submit(function() {
console.log(JSON.stringify($(this)));
var formData = new FormData($(this)[0]);
$.post($(this).attr("action"), formData, function(data) {
alert(data);
});
return false;
});
});
</script>
<form class="form-horizontal" action="/admin" method="post">
<input id="query" type="file">
<input id="query2" type="file">
<button type="submit">Update Data</button>
</form>
Now, in my console I see log that looks like below
In admin method. Request method: GET
In admin method. Request method: POST
**In search method. With request method: GET**
The bolded line is what makes me uncomfortable and looks suspicious to me. When I submit post request to my /admin, why is another GET request executed by flask app ?

#app.route("/<query>", methods=['GET'])
this route is very wide and it grabs all /admin requests. Try to make for example routes /admin/ and /r/

Instead of use:
<form class="form-horizontal" action="/admin" method="post">
You can try this one:
<form class="form-horizontal" action="{{ url_for('admin') }}" method="post">

Related

cannot get flask to upload a file [duplicate]

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>

How to add information in a page without refreshing the page?

I would like to have a page in my django application that has a button that search a product and after selecting quantities gets added to the page (without reloading) in a list where the total get calculated (something like that), I am a beginner in programing and I have a week reading and investigated how to do it but I don't found anything.
Is because you need other programming language? Or could you indicate me some documentation or some example that I can read. Mostly because for my inexperience I don't know how to identify the relevant information in the documentation or even what to look for.
This can be done using Ajax call,
check this example:
forms.py
class sampleForm(forms.Form):
input = forms.CharField()
views.py
from django.http import JsonResponse
def sampleview(request):
input = request.POST.get('input', None)
#perform your logic here
#let us say your data is in variable result
result = {'product1' : 'python' ,'product2' : 'django' , 'product3' : 'ajax' }
return JsonResponse(result)
urls.py
from django.urls import path, include
from . import views
urlpatterns = [
path('sampleview',views.sampleview,name='sampleview'),
]
your HTML
<form method="POST">
{% csrf_token %}
{{form.as_p}}
<button id="sampleform-submit" type="submit">submit</button>
</form>
<div id="results"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script>
$("#sampleform-submt").click(function(){
e.preventDefault();
var form = $('#id_input').closest("form")
//id_input is id of input tag generated by form and above line selects the form
$.ajax({
url : "{% url 'sampleview' %}",
type: "POST",
data : form.serialize(),
dataType: 'json',
success: function(data){
#data is 'result' you return in sampleview function
$("#results").append('<p> '+ data.product1 +'</p>');
$("#results").append('<p> '+ data.product2 +'</p>');
$("#results").append('<p> '+ data.product3 +'</p>');
}
});
}
</script>
I hope this helps

Call function from button in django

On one of my pages I want to display a button, whenever this button is clicked I want to display the following in my display "Button clicked".
However the following message displays in my console.""GET /account/all-plan/?print_btn=Click HTTP/1.1" 200 5025"
This is my view
def print_from_button(request):
if(request.GET.get('print_btn')):
print('Button clicked')
return HttpResponse('testklik')
html
<form method="get">
<input type="submit" class="btn" value="Click" name="print_btn">
</form>
and url in urls.py
path('all-plan/print_from_button', views.print_from_button, name='print_from_button'),
Can anyone point me into the right direction, I cannot find what I am missing. Thanks a lot!
You seem to have to URLs:
/account/all-plan/
/account/all-plan/print_from_button
In the first URL you are creating a <form> which uses the GET method, but no action attribute is specified. The result is that your form submits to the same URL as the current page (first URL). This can be seen as your console print says it's using the first URL with an extra GET parameter.
In order to get your form to use the correct URL you need to specify the action attribute with the correct URL:
<form method="get" action="{% url "app_name:print_from_button" %}">
...
</form>

Django CSRF cookie not set by JS post request

I'm trying to build client/server system as follows: server is django REST with some database, client is static HTML/CSS/JS built as separate django project.
I've got stuck with a basic user authentication scheme processed via simple login form on client side. My idea was to go for token authentication, token to be stored in client's localStorage - so that's why I've taken approach to handle the form submit and POST for token to server by JS.
The issue is I cannot get the token from server to client due to Forbidden (CSRF cookie not set.): /getToken/ error on the server side. Spent tons of time on it and I cannot find answer why CSRF cookie is not set as I enforce at least 4 mechanisms forcing the cookie set: 1) {% csrf_token %}, 2) manual setting of cookie header, 3) #ensure_csrf_cookie, 4) removing 'django.middleware.csrf.CsrfViewMiddleware', from MIDDLEWARE_CLASSES in server settings.py ...
Here are the details:
The client part looks as follows:
login.html form:
<form name="login" method="POST">
{% csrf_token %}
Username<input type="text" name="uname"/>
Password<input type="password" name="psswd"/>
<input type="button" onclick="do_login(this.form)" value="Login"/>
<input type="reset" value="Reset"/>
</form>
where do_login() is in the script below. Pls mind the {% csrf_token %} is included ...
login_script.js :
function do_login(form) {
var csrftoken = getCookie('csrftoken');
uname = form.uname.value;
psswd = form.psswd.value;
var req = new XMLHttpRequest();
var url = "http://localhost:8000/getToken/";
var params = JSON.stringify({ username: uname, password: psswd });
req.open("POST", url, true);
req.setRequestHeader("X-CSRFToken", csrftoken);
req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
req.onreadystatechange = function() {
if(req.readyState == XMLHttpRequest.DONE && req.status == 200) {
alert(http.responseText);
}
}
req.send(params);}
where getCookie is a copy&paste function from django tutorial (it seems to return some cookie, so I assume it's correct)
views.py:
#ensure_csrf_cookie
def user_login(request):
return render(request, 'login.html', {})enter code here
I put #ensure_csrf_cookie to force the cookie input but with no success ...
On the server side I have a view
#require_POST
def getToken(request):
serializer = AuthTokenSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
response = HttpResponse({'token': token.key}, content_type="application/json")
response["Access-Control-Allow-Origin"] = "*"
return response
which is basically the slightly redefined django's built-in obtain_auth_token (as I couldn't overcome CORS issue in any other way round)

Scrapy FormRequest How to check if URL is needed

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.