How to check request method inside Python class? - python

I have a class for Flask:
class Likes(object):
def __init__(self, model, table_id):
self.model = model
self.table_id = table_id
if request.form["likes"] == 'like':
query = self.model.query.filter_by(id=table_id).first()
query.likes += 1
db.session.commit()
flash(u'Like =)) ' + query.title, 'info')
elif request.form["likes"] == 'dislike':
query = self.model.query.filter_by(id=table_id).first()
query.likes -= 1
db.session.commit()
flash(u"Don't like =(" + query.title, 'info')
and I want to call this class every time user sent POST request, but every time I create an instance of my class I need add check request type:
# ...
if request.method == 'POST':
Likes(Post, request.form["post_id"])
# ...
How can I improve my class and add inside it this check:
if request.method == 'POST':
# ...
Solution:
Use decorator #app.before_request
#app.before_request
def before_req():
if request.method == 'POST':
flash(u'Before request', 'success')

You can use Flask.request_started signal to run something everytime a request arrive and then execute the code you require.
flask.request_started
This signal is sent before any request processing started but when the request context was set up. Because the request context is
already bound, the subscriber can access the request with the standard
global proxies such as request.
Have a look at the Flask's Signals chapter to learn more.
Use something like that in your code:
def create_like(sender, **extra):
if request.method == 'POST':
Likes(Post, request.form["post_id"])
from flask import request_started
request_started.connect(create_like, app)
This was adapted from the example for the documentation of Core Signals.

Related

How to redirect to page where request came from in Django

I currently work on a project an i want to redirect to page where request is came form, when request method is GET.
this is my views.py file
Views.py
def delete_patient(request):
if request.method == 'POST':
patient_id = request.POST['patient_id']
rem = Patient.objects.get(pk=patient_id)
rem2 = CustomUser.objects.get(aid=patient_id, role=4)
rem.delete()
rem2.delete()
return JsonResponse({'delete': 1})
else:
// //
so please tell me what I want to write in else part of view.
Typically for that, the server responds with a 405 method not allowed. Especially since it is not even said that the request "comes from somewhere". For example one can make such request with curl, wget, etc. You can work with a #require_POST decorator [Django-doc] for example to return a 405 in case the method is something else than a POST (GET, PUT, PATCH, etc.):
from django.views.decorators.http import require_POST
#require_POST
def delete_patient(request):
patient_id = request.POST['patient_id']
rem = Patient.objects.get(pk=patient_id)
rem2 = CustomUser.objects.get(aid=patient_id, role=4)
rem.delete()
rem2.delete()
return JsonResponse({'delete': 1})
If you really want to redirect to the referring page, you can try to access the HTTP_REFERER key from the request.META dictionary. But not all browsers per se send the referring page, and it is not even said that the request comes from a web client in the first place.
You thus can work with:
from django.http import HttpResponseNotAllowed, HttpResponseRedirect
def delete_patient(request):
if request.method == 'POST':
patient_id = request.POST['patient_id']
rem = Patient.objects.get(pk=patient_id)
rem2 = CustomUser.objects.get(aid=patient_id, role=4)
rem.delete()
rem2.delete()
return JsonResponse({'delete': 1})
elif 'HTTP_REFERER' in request.META:
return HttpResponseRedirect(request.META['HTTP_REFERER'])
else:
return HttpResponseNotAllowed(['POST'])

How to hide POST request on view in django?

I have one view which has POST and GET request. For POST request data comes from other URL. I don't use this view to POST the data. However, I have a GET request for the same view which retrieves data from the model and displays it. Now, when I open (GET request) this view it correctly shows the data. But in addition it shows text area for a POST request as well. I want to hide POST request on my view.
Code:
#api_view(['POST','GET',])
def TestView(request):
if request.method == 'POST':
data = json.loads(request.body.decode('utf-8'))
customers_instance = Customers.objects.create(firstname=data[0]["value"],
lastname=data[1]["value"],
dob=data[2]["value"],
emailaddress=data[3]["value"],
address1=data[4]["value"],
address2=data[5]["value"],
city=data[6]["value"],
state=data[7]["value"],
postalcode=data[8]["value"])
return HttpResponse('Data has been received by API')
if request.method == 'GET':
qs= Customers.objects.values('emailaddress','customer_id')
serializer_class = CustomersKeySerializer
return Response(serializer_class(many=True).to_representation(qs))
Jay,
I think you should use two different views since you are dealing with two different URL's: one for GET and one for POST request.
#api_view(['GET',])
def TestGetView(request):
if request.method == 'GET':
qs= Customers.objects.values('emailaddress','customer_id')
serializer_class = CustomersKeySerializer
return Response(serializer_class(many=True).to_representation(qs))
#api_view(['POST',])
def TestPostView(request):
if request.method == 'POST':
data = json.loads(request.body.decode('utf-8'))
customers_instance = Customers.objects.create(firstname=data[0]["value"],
lastname=data[1]["value"],
dob=data[2]["value"],
emailaddress=data[3]["value"],
address1=data[4]["value"],
address2=data[5]["value"],
city=data[6]["value"],
state=data[7]["value"],
postalcode=data[8]["value"])
return HttpResponse('Data has been received by API')

DRF transmit errors through functions

I know that this question may be already asked or be very obvious but I cannot find anything about it.
Let's say we have this method in views.py:
def my_api_view(request):
if request.method == "POST":
return HttpResponse(other_function())
else:
return HttpResponse("{UERR:%s}" % {UERR_POST_REQUEST_EXPECTED})
where other_function() is a function in another file in another directory outside of Django app:
def other_function():
a = function1()
b = function2()
return function3(a,b)
Question: If something goes wrong in other_function(), function1(), function2() or function3(a,b) how do we make our view to return an HttpResponse with an error? For example, if function1() access an unavailable resource.
An HttpResponse with an error is usually just a response with a 400 status code (indicating an error with the clients request, not your server)
def my_api_view(request):
if request.method == "POST":
return HttpResponse(other_function())
else:
return HttpResponse("{UERR:%s}" % {UERR_POST_REQUEST_EXPECTED}, status=400)
If you're using rest framework, the convention is to return rest_framework.response.Response though.
from rest_framework.response import Response
from rest_framework import status
def my_api_view(request):
if request.method == "POST":
return Response(other_function())
else:
return Response("{UERR:%s}" % {UERR_POST_REQUEST_EXPECTED}, status=status.HTTP_400_BAD_REQUEST)

Flask-Cache doesn't distinguish between GET and POST

I have a Flask route structured like so:
#app.route('/rootpath1/<path:path>')
#app.route('/rootpath2/<path:path>', methods=['GET', 'POST'])
#cache.cached()
def rootpath():
...
POSTs to '/rootpath2/' for a given page are typically retrieved from cache (when a cached value is present), which is usually the last GET request.
For example, a user would visit '/rootpath2/myform', fill out and then submit the form. The form would post to '/rootpath2/myform' and the user would be returned to the same URI with a message indicating that the form submission was successful (or that errors occurred, if they did).
The problem here is that a GET always precedes the POST, and the POST always triggers a cache hit and returns that value.
Is there a way for Flask-Cache to distinguish between GETs and POSTs and handle them according (only caching GETs)?
Yes. The cache decorator provides an unless kwarg that accepts a callable. Return True from the callable to cancel caching. Test it out with the following:
from flask import Flask, request, render_template_string
from flask.ext.cache import Cache
app = Flask('foo')
cache = Cache(app,config={'CACHE_TYPE': 'simple'})
t = '<form action="/" method="POST">{{request.form.dob}}<input name="dob" type="date" value={{request.form.dob}} /><button>Go</button></form>'
def only_cache_get(*args, **kwargs):
if request.method == 'GET':
return False
return True
#app.route('/', methods=['GET', 'POST'])
#cache.cached(timeout=100, unless=only_cache_get)
def home():
if request.method == 'GET':
print('GET is not cached')
return render_template_string(t)
if request.method == 'POST':
print('POST is not cached')
return render_template_string(t)
app.run(debug=True)

How to pass a "WTF object" in Flask

I am using flask to develop a website and now i encountered a problem.
I am thinking whether I can pass a "WTF form" object in flask.
Like,
#app.route('/')
#app.route('/index')
#login_required
def index():
user = flask.g.user
form = PostForm()
return flask.render_template("index.html",
title="Home",
user=user,
form = form)
This form, an instance of PostForm, actually will be processed by the following code:
#app.route('/note/<int:id>', methods=['POST'])
def note(id):
form = ?(how to get this form?)?
if form.validate_on_submit():
print id
content = form.body.data
currentTime = time.strftime('%Y-%m-%d', time.localtime(time.time()) )
user_id = id
return flask.redirect(flask.url_for('login'))
return flask.redirect( flask.request.args.get('next') or
flask.url_for('index') )
In the template, I set the action to be "/note/1", so it will forward to this address. But the question, how can I get the form created in the function index?
I have tried to use flask.g (Obviously, it does not work because it's another request). And I also tried to use global variable. It failed, either.
Could anyone give me a solution or any advice?
Thank you in advance!
You simply need to construct a new version of PostForm in your note route and use the posted data in request.form:
from flask import request
#app.route('/note/<int:id>', methods=['POST'])
def note(id):
form = PostForm(request.form)
# or, if you are using Flask-WTF
# you can do
# form = PostForm()
# and Flask-WTF will automatically pull from request.form

Categories

Resources