How to hide variables from flask url routing? - flask

I'm making API and looking for a way to hide the extra information from the url. I have a function index:
#app.route('/', methods=['GET', 'POST'])
def index():
count = foo()
return redirect(url_for("result", count=count))
and a function result
#app.route("/done/<count>")
def result(count):
count = count
return jsonify(count=count)
Inner function count allwase return different values. At the end I get a result like
http://127.0.0.1:5000/done/43
But I need more common url view for universal API like
http://127.0.0.1:5000/done
The problem is that if I remove <count> from endpoint, i get error
TypeError: result() missing 1 required positional argument: 'count'
Is there a way to override this?

This task solving by session variable
from flask import session
#app.route('/', methods=['GET', 'POST'])
def index():
count = foo()
session['count'] = count
return redirect(url_for("result"))
#app.route("/done/")
def result(count):
count = session['count']
return jsonify(count=count)

Related

same function but 2 different route and render 2 different templates

i want to know how use same function but 2 different route and render 2 different templates, the way i see is to do like this:
#app.route('/analysis_equipment_overview_approvalviewv2/<prelim_uid>', methods=['GET', 'POST'])
def analysis_equipment_overview_approvalviewv2(prelim_uid):
#same logic here
return render_template('template_1.html')
app.route('/analysis_equipment_overview_approvalview/<prelim_uid>', methods=['GET', 'POST'])
def analysis_equipment_overview_approvalview(prelim_uid):
#same logic here
return render_template('template_2.html')
is there any way to reduce the lines, especially when the logic is too long and avoid to write it twice?
I find this way, but need clean code at pattern regex with constant.
#app.route('/analysis_equipment_overview_approvalviewv2/<prelim_uid>', methods=['GET', 'POST'])
#app.route('/analysis_equipment_overview_approvalview/<prelim_uid>', methods=['GET', 'POST'])
def analysis_equipment_overview_approvalview(prelim_uid):
#same logic here
if re.search(r'/analysis_equipment_overview_approvalviewv2/', request.full_path):
return render_template('template_2.html')
return render_template('template_1.html')

django path is not recognizing its intended view

code: urls.py
path('tools/<int:rate>/', ToolsView.as_view(), name="get-all-tools"),
path('tools/post/', ToolsView.as_view(), name="save-tool"),
code: views.py
class ToolsView(APIView):
def get(self, request, rate):
objs = ToolsModel.objects.values_list()[:rate]
if objs is None:
return Response(status=status.HTTP_404_NOT_FOUND)
data = []
for obj in objs:
print(obj)
json = {}
json['toolid'] = obj[0]
json['tool_name'] = obj[1]
json['tool_from'] = obj[2]
json['tool_qty'] = obj[3]
json['tool_state'] = obj[4]
data.append(json)
return Response(data=data, status=status.HTTP_200_OK)
def post(self, request):
data = request.data
serialize = ToolsSerializer(data=data)
if serialize.is_valid():
serialize.save()
return Response(status=status.HTTP_201_CREATED)
return Response(status=status.HTTP_404_NOT_FOUND)
Whenever i call for tools/post/ intended to call post method
http://127.0.0.1:8000/help/tools/post/
i get
get() missing 1 required positional argument: 'rate'
but rate parameter is actually needed for 'tools/<int:rate>/' which invokes my get method ,example,
http://127.0.0.1:8000/help/tools/5/
Needed help with these. Thanks in advance!
if you put http://127.0.0.1:8000/help/tools/post/ into your browser, you will be performing a GET on the URL. In your urls.py you map that route to ToolsView.as_view(). This allows you to handle the different HTTP Methods via functions. So def post will get called when a POST is requested. But you are likely doing a GET, which will call the def get(...) method. But because you aren't passing in a rate it's missing from the function arguments, hence the error. To test the post method you need to perform a POST to http://127.0.0.1:8000/help/tools/post/.
Test Code:
import requests
requests.post("http://127.0.0.1:8000/help/tools/post/", data={})

Flask Passing Form argument to a function

I am new to Flask and I am just trying to pass 4 arguments that I got from my form to another python function. When I submit my form, I am getting this error : "TypeError: search() missing 4 required positional arguments: 'keywords', 'starting_date', 'ending_date', and 'country'"
I verified and all of my variables have data from the form, so they are not empty
`
#app.route('/')
#app.route('/index', methods=["GET", "POST"])
def index():
if request.method == "POST":
keywords = request.form.get('keywords')
starting_date = request.form.get('starting_date')
ending_date = request.form.get('ending_date')
country = request.form.get('country')
return redirect(url_for("search", keywords=keywords, starting_date=starting_date, ending_date=ending_date, country=country))
else:
return render_template("index.html")
#app.route('/search', methods=["GET"])
def search(keywords, starting_date, ending_date, country ):
return render_template('result.html', title='Result')
You'll need to define your search route as
#app.route('/search/<keywords>/<starting_date>/<ending_date>/<country>', methods=["GET"])
to get your current implementation to work, see Variable Rules section in Flask's doc.
This is, however, problematic. For one, you probably don't want such a messy URL.
A better approach is to ask Flask to send your data to search as query parameters and retrieve it through request.args. Redefine search as
#app.route('/search', methods=["GET"])
def search():
keywords = request.args['keywords']
starting_date = request.args['starting_date']
ending_date = request.args['ending_date']
country = request.args['country']
# perform search
return render_template('result.html', title='Result')
Now url_for will generate a URL of the form /index?keywords=<value>&starting_date=<value>....
See this great SO answer for all the ways to get data from a request: https://stackoverflow.com/a/16664376/1661274
You need to render the template with your form parameters.
Try this:
#app.route('/index', methods=["GET", "POST"])
def index():
if request.method == "POST":
keywords = request.form.get('keywords')
starting_date = request.form.get('starting_date')
ending_date = request.form.get('ending_date')
country = request.form.get('country')
return render_template('result.html', keywords=keywords, starting_date=starting_date, ending_date=ending_date, country=country)
else:
return render_template("index.html")

Django reverse 'str' object has no attribute 'get'

I am trying to use reverse method in django view but I got an exception 'str' object has no attribute 'get'.
here is my view
class AbandonTicketView(View):
context = dict()
template_name = "places/order_detail.html"
def get(self, request, uidb64, token, ordercode):
order = abandon_oder(uidb64, token, ordercode)
if order is not None and order.paid is False:
return reverse("order_detail", kwargs={"ordercode": order.code})
return redirect("tickets")
view that I want to go:
class OrderDetailView(LoginRequiredMixin, View):
template_name = "places/order_detail.html"
context = dict()
def get(self, request, ordercode):
order = Order.objects.get(code=ordercode)
self.context["order"] = order
self.context["key"] = settings.tycoon.STRIPE_PUBLISHABLE_KEY
if order.send_count >= 3 and order.paid is False:
self.context["abandon_ticket"] = "Order was canceled"
return render(request, template_name=self.template_name, context=self.context)
def post(self, request, ordercode):
order = pay_for_ticket(ordercode, request.POST["stripeToken"], request.user)
self.context["order"] = order
return render(request, template_name=self.template_name, context=self.context)
here is url:
path("orders/<code:ordercode>/detail/", views.OrderDetailView.as_view(), name="order_detail"),
path("tickets/", views.OrderedTicketsView.as_view(), name="tickets"),
I don't really know why it happends, because I do the similar reverse earlier and everything works fine, but not now. Could you help me please to solve this problem?
reverse() returns a string, but your view has to return a HttpResponse.
Change your line:
return reverse("order_detail", kwargs={"ordercode": order.code})
to also use redirect() (like the other part of your view)
return redirect("order_detail", args=[order.code, ])
or maybe even simplified like this
return redirect("order_detail", order.code)
Does that work?
You could use redirect with reverse and it works.
from django.shortcuts import redirect
return redirect(reverse("order_detail", kwargs={"ordercode": order.code}))
OR the second keyword to do the same thing is:
from django.http import HttpResponseRedirect
return HttpResponseRedirect(reverse("order_detail", kwargs={"ordercode": order.code}))
The reasoning behind this is that reverse just returns the URL in the form of a string. When you want to redirect an HTTP Response should happen. Only cases where only the URL is required reverse should be used otherwise you need to generate an HTTP Response as well.

views didn't return an HttpResponse object. It returned None instead

I'm implementing some search mechanism on my app, trying to get the query from input, look for it in database(sqlite) and render it to template. Problem is that I'm getting error:
.views didn't return an HttpResponse object. It returned None instead.
Logic is like:
1) making a function which will check given query
def search_query(request,search,query):
checking = check_in(query) #check if query is in DB
if checking == False: #if not, get data from search api and save it
search_querys = requests.get(search)
json_search = search_querys.json()
for each in json_search['data']:
user_id = each['id']
name = each['name']
picture = each['picture']['data']['url']
Profiles.objects.create(user_id=user_id, name=name, picture=picture)
return render(request, 'FB_search/home.html')
else: # <--assuming that here's the problem. For testing purpose, I'm writing query for which I know that they are in DB and I'd like to return in tamplet
context = {
'profiles': Profiles.objects.filter(Q(user_id__startswith=query) | Q(name__startswith=query))
}
return render(request, 'FB_search/home.html', context)
2) calling function above in my endpoint like:
def api_search(request):
if request.method == "GET":
query = request.GET.get('q')
search = 'some API with {query} inside it'
search_query(request,search,query)
When I try to call the "search query" funtion I'm getting mentioned error.
Any suggestion?
Thank you.
You are not returning the return value of search_query, you should return it:
def api_search(request):
if request.method == "GET":
query = request.GET.get('q')
search = 'some API with {query} inside it'
return search_query(request,search,query)