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)
Related
I'm new to Django Class Based Views and I can't get my form to pass through neither form_valid() nor form_invalid().
I have taken most of this code from the Django allauth module, so I extend some mixins (AjaxCapableProcessFormViewMixin & LogoutFunctionalityMixin) that I do not know well.
This form is meant to allow users to change their passwords upon receiving an email. As it is now, users are able to change their password but since the form_valid() function is never triggered, they do no get redirected to the success URL as is intended. Instead the password change is registered but the users stay on the same page.
The functions dispatch(), get_form_kwargs() & get_form_class() are all triggered and behave in the way that they should. Still, it's unclear to me why they execute in the order that they do (dispatch() is triggered first, then get_form_class() and finally get_form_kwargs(). I suppose they implicitely have an order as presented in this documentation: https://ccbv.co.uk/projects/Django/4.0/django.views.generic.edit/FormView/)
I am lacking some intuition about how this works, therefore I don't know if there is a way to redirect to the success URL without passing through form_valid() because that would also solve my problem.
As is mentionned in the title, neither form_valid() nor form_invalid() is triggered after submitting a new password. The last executed bit of code is the return kwargs from the get_form_kwargs() function.
Here is my code:
class PasswordResetFromKeyView(AjaxCapableProcessFormViewMixin, LogoutFunctionalityMixin, FormView):
template_name = "account/password_reset_from_key." + app_settings.TEMPLATE_EXTENSION
form_class = ResetPasswordKeyForm
success_url = '/'
reset_url_key = "set-password"
def get_form_class(self):
return get_form_class(
app_settings.FORMS, "reset_password_from_key", self.form_class
)
def dispatch(self, request, uuid, **kwargs):
self.request = request
token = get_object_or_404(ResetToken, token=uuid)
if token.redeemed == False:
self.reset_user = token.client
self.token = token
response = self.render_to_response(self.get_context_data(token_fail=False))
else:
return super(PasswordResetFromKeyView, self).dispatch(
request, uuid, **kwargs
)
return response
def get_form_kwargs(self, **kwargs):
kwargs = super(PasswordResetFromKeyView, self).get_form_kwargs(**kwargs)
kwargs["user"] = self.reset_user
if len(kwargs) > 3:
try:
if kwargs['data']['password1'] == kwargs['data']['password2']:
self.reset_user.set_password(kwargs['data']['password1'])
self.reset_user.save()
self.token.redeemed = True
self.token.date_redeemed = datetime.now()
self.token.save()
perform_login(
self.request,
self.reset_user,
email_verification=app_settings.EMAIL_VERIFICATION,
)
else:
pass
##passwords dont match
except:
##couldnt change the password
pass
return kwargs
def form_valid(self, form, **kwargs):
form.save()
return super(PasswordResetFromKeyView, self).form_valid(form)
def form_invalid(self, form):
response = super().form_invalid(form)
if self.request.accepts('text/html'):
return response
else:
return JsonResponse(form.errors, status=400)
If both methods are not triggered, it means - you requests.method is never is 'POST'.
The class FormView calls this two methods only if post.method == 'POST':
# code from django.views.generic.edit
...
def post(self, request, *args, **kwargs):
"""
Handle POST requests: instantiate a form instance with the passed
POST variables and then check if it's valid.
"""
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
By the way in dispatch, if token.redeemed == False you should return self.form_invalid().
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'])
Got a real problem here. I have got 2 views in backend and really need to redirect FROM second view
Views like this:
def first_function(request):
""" Here is some stuff """
second_function(request)
return render(request, 'first.html', context)
def second_function(request)
""" Check here something """
if ok:
return
else:
return redirect('/') # this redirect does not work
Your view second_function returns a response. As long as the view doesn't raise an exception, your first_function will continue, whatever the status code of that response.
If you want to return the redirect, then you'll have to assign the result to a status code, then you'll have to assign the result of second_function to a variable, then check the status code.
def first_function(request):
""" Here is some stuff """
response = second_function(request)
if response.status_code == '302':
return response
return render(request, 'first.html', context)
This isn't a good way to structure your code, but I can't suggest an alternative because your code show what you're really trying to do.
The view below is gives me the error when using the POST method. I'm trying to load the model data into a form, allow the user to edit, and then update the database. When I try to Save the changes I get the above error.
def edit(request, row_id):
rating = get_object_or_404(Rating, pk=row_id)
context = {'form': rating}
if request.method == "POST":
form = RatingForm(request.POST)
if form.is_valid():
form.save()
return redirect('home.html')
else:
return render(
request,
'ratings/entry_def.html',
context
)
Here is the trace from the terminal.
[15/Apr/2016 22:44:11] "GET / HTTP/1.1" 200 1554
[15/Apr/2016 22:44:12] "GET /rating/edit/1/ HTTP/1.1" 200 919
Internal Server Error: /rating/edit/1/
Traceback (most recent call last):
File "/Users/michelecollender/ENVlag/lib/python2.7/site-packages/django/core/handlers/base.py", line 158, in get_response
% (callback.__module__, view_name))
ValueError: The view ratings.views.edit didn't return an HttpResponse object. It returned None instead.
You are redirecting if form.is_valid() but what about the form is invalid? There isn't any code that get's executed in this case? There's no code for that. When a function doesn't explicitly return a value, a caller that expects a return value is given None. Hence the error.
You could try something like this:
def edit(request, row_id):
rating = get_object_or_404(Rating, pk=row_id)
context = {'form': rating}
if request.method == "POST":
form = RatingForm(request.POST)
if form.is_valid():
form.save()
return redirect('home.html')
else :
return render(request, 'ratings/entry_def.html',
{'form': form})
else:
return render(
request,
'ratings/entry_def.html',
context
)
This will result in the form being displayed again to the user and if you have coded your template correctly it will show which fields are invalid.
I was with this same error, believe it or not, was the indentation of Python.
your error to the indentation of a Python file. You have to be careful when following tutorials and/or copy-pasting code. Incorrect indentation can waste lot of valuable time.
You Should Return What file you are rendering instead of Direct Render.
def index(request):
return render(request, 'index.html')
def login(request):
return render(request,'login.html')
def logout(request):
return render(request,'index.html')
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.