I have created a sort of a "Postman" app for my colleagues and me. So, basically worked great with GET method only and I thought why not making DELETE, PUT, POST methods so we can have complete tool.
What I am trying to do is to fire an API call based on a button clicked in a html form. Here is my code with three files, template one, routes and methods files:
<form method="post" action="{{ url_for('api_dashboard.get_customer', store_id=store_id, customer_id=customer_id) }}">
<label class="rc_form__label" for="customer_id">Customer ID</label>
<div class="inputContainer">
<input type="text" class="rc_form__input mb-4 mr-4" placeholder="ex. 123" name="get_customer_id" id="customer_id"/>
<button type="submit_button" id="get_customer" name="get" class="rc_button rc_button--small rc_button--primary">GET</button>
<button type="submit_button" id="delete_customer" name="delete" class="rc_button rc_button--small rc_button--primary">DELETE</button>
<button type="submit_button" id="put_customer" name="put" class="rc_button rc_button--small rc_button--primary">PUT</button>
<button type="submi_button" id="post_customer" name="post" class="rc_button rc_button--small rc_button--primary">POST</button>
</div>
</form>
This is my routes code:
#api_dashboard.route("/<store_id>/customers", methods=["GET", "POST"])
def get_customer_by_id(store_id):
customer_id = request.form.get("customer_id")
if request.method == "POST":
if request.form["submit_button"] == "get_customer":
get_customer = Customer(store_id).get_customer(customer_id)
return render_template(
"/api_dashboard/index.html",
result=json.dumps(get_customer, indent=4, default=str),
store_id=store_id,
customer_id=customer_id,
)
elif request.form['submit_button'] == 'delete':
pass # this will be logic for deleting one
else:
pass # I will continue with other methods
elif request.method == "GET":
return render_template("/internal/api_dashboard/index.html", store_id=store_id)
And this is methods file:
class Customer(ApiService):
def get_customer(self, customer_id):
customer = self.api.get(endpoint=f"/customers/{customer_id}")
return customer.json()
def delete_customer(self, customer_id):
delete_response = self.api.delete(endpoint=f"/customers/{customer_id}")
return jsonify({"Customer deleted"}), 204
The error I am getting is this one:
{
"error": "The browser (or proxy) sent a request that this server could not understand."
}
I have found an article on StackOverFlow but really could not understand what would be the solution in this case. When making condition by the button, not sure what I should look for - and id, name or value of the button field.
My first official dev project in Flask, hope you understand if this is stupid question. Thanks in advance!
Related
I'm trying to create a search bar where it will send users to certain URLs based on the query they typed on the "result" page, e.g. "/results?<form_search>". I've successfully made the version where the result page URL is /results but this isn't really what I want.
Here's the HTML script:
<!--index.html-->
<form action="{{ url_for('search') }}" method="post">
<input type="text" id="search" name="form_search" placeholder="Type here">
</form>
Here's the Python script where I direct the result to /results URL:
#app.py
#app.route("/")
def index():
return render_template("index.html")
...
# I want to direct this to "/results?<form_search>"
# I think I need to put the line below somewhere but I'm not sure where
# form_search = request.form.get("form_search")
#app.route("/results", methods=["POST"]) # Want to change it to "/results?<form_search>"
def search(form_search):
...
return render_template("results.html", form_search=form_search, results=results)
Anyone can help?
I barely worked with flask but if you want to have the dynamic URL you need to add it in your #app.route decorator, e.g.: If I want a username to be posted in the URL this is what it would look like:
#app.route("/<username>") # str,int,uuid,float,path also works
def user_name(username=None, post_id=None):
return render_template("index.html", name=username)
When it comes to getting the data from the form I can show you a similar example as I did in django (I didnt work with flask a while so you might need to experiment a bit yourself) - This is a method as it is created in a class:
def get_queryset(self):
query = self.request.GET.get(
"searchrecipe") # searchrecipe is the name of our input form, means: the value we enter in the form -> This might also work for FLASK, get the data with request.get and FORM NAME
object_list = Recipe.objects.filter(name__icontains=query) #This filters the data in my database (aftger name) so not relevant for you
return object_list
I am trying to create code for my Django site which will take the user's input, perform a calculation, and then send the data back to the user in the form of a new page, however everytime I run the code, it does not create the new page nor does it post the results.
Below is the function itself.
def SparkCalc(request):
new_item = sparkCalculator()
new_item.tix = request.POST['tix']
new_item.tenrolls = request.POST['tenrolls']
new_item.crystals = request.POST['crystals']
new_item.save()
total = new_item.getTotal()
return render(request, 'SparkResults.html', {"title": "Spark Results"}, {"total": total})
and below is the Django page I am calling it from:
<form action="/SparkCalc/" method="POST">{% csrf_token %}
<label for ="tix">Please enter your single roll tickets</label>
<input type="text" id="tix" name="tix"/>
<label for ="tenrolls">Please enter your ten-roll tickets</label>
<input type="text" id="tenrolls" name="tenrolls"/>
<label for ="tix">Please enter your total crystal amount</label>
<input type="text" id="crystals"name="crystals"/>
<input type="submit" value="Get Results"/>
</form>
And finally below is the class I created:
class sparkCalculator(models.Model):
tix = models.PositiveIntegerField()
tenrolls = models.PositiveIntegerField()
crystals = models.PositiveIntegerField()
def getTotal(self):
return (int(self.tix)*300) + (int(self.tenrolls)* 3000) + int(self.crystals)
The way I envision the code to work is that once the user enters their information into the form, Django then runs the SparcCalc function, collecting the information entered, performing the math and collecting a total, and then sending the total to the new page. Instead, it seems to be just refreshing the page.
Also is it possible to run this style of code without creating an entire class for it? This is not information I would want to store. Ideally I would just want it executed at runtime and to be done with it, but previous attempts at doing this have failed and I simply gave up and tried creating a class.
As far as I can tell it is correctly entered into my urlpatterns.
from catalog.views import (
SparkCalc,
sparkCalcPage,
)
urlpatterns = [
path('SparkCalc/', sparkCalcPage),
path('SparkResults/', SparkCalc),
]
Any help would be greatly appreciated and thank you in advance for your help.
The signature of render function is as follows:
def render(request, template_name, context=None, content_type=None, ...):
...
In your case, you have passed {'total':total} to the content_type keyword argument instead of context.
# also make sure 'SparkResults.html' can be found by the template loader
render(request, 'SparkResults.html', {"title": "Spark Results", "total": total})
Also, you need to submit your data to the corrent view.
<form action="/SparkResults/" method="POST">
{% csrf_token %}
...
</form>
Instead of creating a model for the task,
perform the operation in the views.py itself.
def SparkCalc(request):
tix = request.POST['tix']
tenrolls = request.POST['tenrolls']
crystals = request.POST['crystals']
total = (int(tix)*300) + (int(tenrolls)* 3000) + int(crystals)
return render(request, 'SparkResults.html', {"title": "Spark Results"}, {"total": total})
I am creating an app that does some analysis, given a user enters in some IDs into the form. For example, if a user types 12345, 23456 into the TextField form, the app will run some analysis on these IDs and then display the results. My problem is that currently, when the user clicks "Submit" and the data analysis completes, it always redirects the user to www.website.com/results. I need to create unique url's like www.website.com/results/12345+23456 so that 1) I can have multiple users and 2) users can send this link to people to re-generate the analysis.
Now, there are some questions on StackOverflow that are similar to my question but they are not the same and did not help me. So first, let me show some code before discussing that.
I have a home page which contains the the form:
<div>
<form action="https://website.com/results/" class="form-inline" method="post">
<div class="form-group">
<label for="PubmedID">Pubmed ID(s)</label>
<input type="text" class="form-control" id="PubmedID" name="pmid" value="{{request.form.pmid}}">
</div>
<button type="submit" id= "myButton" class="btn btn-default" data-toggle="modal" data-target="#myModal">Submit</button>
</form>
</div>
As you can see, the value for the form is request.form.pmid. My Flask-Wtform for this is here:
class pmidForm(Form):
pmid = TextField('PubmedID')
Since the action of this form points towards website.com/results that triggers my Flask function to be called:
#app.route('/results/', methods=["POST"])
def results():
form = pmidForm()
try:
if request.method == 'POST':
#entry = request.form or request.data doesn't help me...
entry = form.pmid.data #This is the user input from the form!
# DO LOTS OF STUFF WITH THE ENTRY
return render_template('results.html')
except Exception as e:
return(str(e))
As you can see I am using POST and form.pmid.data to get the data from the textfield form.
Again, I don't want to just redirect to /results, I'd like to expand on that. I tried to modify my form so that the form action pointed to https://website.com/results/{{request.form.pmid}}/ and then update the results function to be
#app.route('/results/<form_stuff>', methods=["POST"])
def results(form_stuff):
But this never worked and would re-direct me to a 404 not found page. Which I believe makes sense because there is no form data in the action when the HTML is first rendered anyway.
Now, the other post that mine is similar to is: Keeping forms data in url with flask, but it quite doesn't answer or solve my problem. For tthis post, the key point that people made was to use POST (which I already do), and to obtain and return the data with return request.args['query']. For me, I'm already processing the form data as I need to, and I have my return render_template() exactly how I want it. I just need to add something to the results URL so that it can be unique for whatever the user put into the form.
What do I need to add to my form in the html and to my Flask /results function in order to have the form data added into the URL? Please let me know if there's any other information I can provide to make my problem more clear. I appreciate the help! Thanks
This isn't really a question about Flask.
If you want the data to show in the URL when you submit the form, you should use method="get" rather than "post". Then the URL will be in the form https://website.com/results/?pmid=12345.
I have to delete database entries conditionally and I couldn't figure out as the form is asking for correct parameters posted in uri. I can delete entries in shell with same code but not in view. Following is the view and form:
#app.route('/cancelannualsub/<int:student_id>', methods=['DELETE'])
def cancel_yearly_rec(student_id):
if not user_authorized():
return redirect('/')
user = get_profile_data(session['auth_token'])
profile_data = user['StudentProfile']
pkg = Package.query.filter_by(student_id=profile_data.id).first_or_404()
if request.method=='POST':
try:
pkg = Package()
dbase.session.delete(pkg)
flash('Package deleted successfully.')
dbase.session.commit()
except:
pass
return redirect('plans')
return render_template('profile/cancel/cancel.html')
Form:
<form action="{{ url_for('cancel_yearly_rec', student_id=***can't render value here***) }}" method='post'>
<input type='hidden' name='_method' value='DELETE'
<input class='btn' type="submit" value="Cancel" />
</form>
I am trying different things from stackoverflow examples. Please assist if I am doing something wrong or if there is a better way to do it.
I wasn't using proper formatting to render model objects inside try block.
It supposed to be something like:
mymodel = Model.query.filter_by(variable=some_field_data).first_or_404()
dbase.session.delete(mymodel)
dbase.session.commit()
For readers don't get confused with "dbase" because I made this import like:
from app import db as dbase
You can import it simply by:
from app import db
or add "as anything".
Then you reference anything in rest of your file where you've made import.
This is a function which (in a GET request) receives a case_url and case_key and serves the corresponding case (using mongoDB) to a html template called detail_case.
Im trying to add a feature where when a form is filled(on this same page detail_case) and it is submitted, it should submit a POST request to the same function and the code under 'if request.method=="POST"' should get executed.
#app.route('/case/<case_url>/<case_key>', methods=["GET","POST"])
def serve_case(case_url,case_key):
"""for saving a comment in db.comments"""
if request.method == "POST":
text=request.form['comment_text']
#code which inserts it in the database
return redirect(url_for('serve_case', \
case_url=case_url,\
case_key="Highlights"))
"""
Function serves the case as per the key indicated in the URL
"""
#corresponding code here which fills values of variables and sends it to another page
return render_template('detail_case.html')
The problem is that I don't think the POST request is ever executed. This is the html code on the template page detail_case-
<textarea placeholder="Please enter your comments here" action="{{ url_for('serve_case',case_url=case_url,case_key=case_key)}}" method="POST" name="comment_text" rows="6"></textarea><br />
The problem i think is the action field. I don't know how should I send the variable comment_text to my function. Infact, the code under POST does not get executed when I submit.
Basically the issue is that during a GET request, it sends 2 variables which are needed in the parameters of the function serve_case. During my POST request, well, I don't know how to exactly frame the action field. If I send no parameters, its an error. If I don't send it to the same function, then how will it execute the POST code? Could someone please suggest sumthing?
i'm pretty new to flask, i'm editing someone else's code
You need to submit the POST request (for example through form) like below:
<form action="{{ url_for('serve_case',case_url=case_url,case_key=case_key)}}" method="POST">
<input type="text" placeholder="Please enter your comments here">
<input type="submit" name="comment_text" rows="6"><br />
</form>