Cancel the POST when the page is refreshed - python

My problem is: when an user refresh a form, the data in the Form is sent.
I have a Form with a POST request.
The user writes his name, mail and a message. If the mail is correct, the message is sent.
In my view, if the Form is valid, I add the message in my model Message.
After that I disable the "Send" button. But if the user refreshes the page, my view is called, and another row is added in my model.
I would like, when the user refreshes the page, to block the POST.
My View:
def contact(request):
form = MessageForm(request.POST or None)
if form.is_valid():
name = form.cleaned_data['name']
message = form.cleaned_data['message']
mail = form.cleaned_data['mail']
new_message = Message()
new_message.name = name
new_message.message = message
new_message.mail = mail
new_message.save()
envoi = True
return render(request, 'vautmieux/contact.html', locals())
My URL:
path('contact/', views.contact, name='contact'),
My HTML:
<form action="{% url "contact" %}" method="post">
{% csrf_token %}
<div class="row">
<div class="col-md-6">
{{ form.name }}
{{ form.mail }}
</div>
<div class="col-md-6" >
{{ form.message }}
</div>
<button id="sendMessageButton" type="submit">ENVOYER LE MESSAGE !</button>
</div>
{% if envoi %}Votre message a bien été envoyé !{% endif %}
</form>

This is the main reason why people implement the Post/Redirect/Get pattern [wiki]. In case of a successful POST request, you should return a redirect to a URL. As a result the browser will perform a GET, and in case the browser thus performs a refresh later, it will make a GET again.
def contact(request):
if request.method == 'POST':
form = MessageForm(request.POST)
if form.is_valid():
form.save()
return redirect('some-message-successful-view')
else:
form = MessageForm()
return render(request, 'vautmieux/contact.html', {'form': form})
Here 'some-message-successful-view' needs to be replaced with the name of a view you trigger when sending a message was succesful. This can be the same view as the one defined here. I advice to use Django's message framework [Django-doc] to send a message to the user that the message has been submitted successfully.

Related

Django restricting users from updating/deleting other users posts

views.py
#login_required(login_url='/login')
def updatepost(request,pk):
post = Post.objects.get(id=pk)
form = PostForm(instance=post)
if request.method =='POST':
form = PostForm(request.POST, request.FILES, instance=post)
if form.is_valid():
form.save()
return redirect ('mainpage')
context = {'form':form}
return render( request, 'postform.html', context )
postform.html
{% include 'main.html'%}
{% block content %}
{%if user.is_authenticated%}
{% if user.id == post.user.id%}
<div>
<form method="POST" action ="">
{% csrf_token %}
{{form.as_p}}
<input type="Submit" value ="Submit"/>
</form>
</div>
{%endif%}
{%endif%}
{% endblock content %}
I am trying to restrict user who is logged in - from updating , deleting other users posts.
However when I Try to use {% if user.id == post.user.id%} , the page becomes blank even for the user who is editing his own post. The same goes for deleting.
It works on mainpages - where posts are displayed (it hides edit and delete buttons).
What is the reason that the post is not showing inside the template ?
I don't understand that even {{post.user}} in postform.html does not appear , neither on deleteform etc. - why this data of objects of a post is not being sent to postform.html ?
You should change the context to access the post instance from your template.
context = {'form': form, 'post': post}
You can only access the context values from the templates. So pass the ones you want to use while you are returning a response.

how can I use LoginView in my own view and show in HTML templates?

I want to use ready Django LoginView, but in the same time I have to use my own view for registration in same HTML template. If in urls.py file I will connect 2 views than i will connect only first. So my question is that how can use LoginView in my own view and use 2 forms with jinja?
here is my views.py file and html ;)
def index(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
formlog = auth_views.LoginView.as_view(template_name='main/index.html')
if 'signup' in request.POST:
if form.is_valid():
form.supervalid()
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Dear {username} you have been created a new accound!')
return redirect('main')
elif 'login' in request.POST:
if formlog.is_valid():
formlog.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in')
return redirect('main')
else:
form = UserRegisterForm()
formlog = auth_views.LoginView.as_view(template_name='main/index.html')
return render(request, 'main/index.html', {'form': form, 'formlog': formlog})
# this code is not working , but not returning any errors
HTML
{% if not user.is_authenticated %}
<!-- Login -->
<div class="container">
<div class="log-1">
<div class="log-0">
<p class="logtitle">BareTalk</p>
<form method="POST" name="login">
{% csrf_token %}
{{ formlog|crispy }}
<button class="log-button first" type="submit">Login</button>
</form>
<button class="log-button second"
onclick="modalwindowops.open();" id="signup">Sign Up</button>
</div>
</div>
</div>
<!-- Signup -->
<div class="modal-overlay">
<div class="modal-window">
<span class="close-modal" onclick="modalwindowops.close();">×</span>
<form method="POST" name="signup">
<p>Sign Up</p>
{% csrf_token %}
{{ form|crispy }}
<button type="submit">Sign Up</button>
</form>
</div>
</div>
{% else %}
<h1>Welcome back Amigo!</h1>
{% endif %}
Neither if 'signup' in request.POST: nor elif 'login' in request.POST: is triggered in your index() view because your HTML forms do not actually contain those inputs. Note that the name attribute is deprecated for the <form> element.
Instead you can add a hidden <input> inside your forms, like this:
<form method="POST">
{% csrf_token %}
{{ formlog|crispy }}
<input type="hidden" name="login" value="true" />
<button class="log-button first" type="submit">Login</button>
</form>
Also,
formlog = auth_views.LoginView.as_view(template_name='main/index.html')
saves a view to formlog, not a form, so calling formlog.is_valid() will cause an error.
Instead of
elif 'login' in request.POST:
if formlog.is_valid():
formlog.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Your account has been created! You are now able to log in')
return redirect('main')
you probably will only need to do
elif 'login' in request.POST:
log_view = auth_views.LoginView.as_view(template_name='main/index.html')
log_view(request)
Calling is_valid(), save(), and doing the redirect is all done by LoginView already. If you want to still do the custom message.success() you will have to override one or more of the LoginView methods, but that is another topic.
Update:
You also need to change this line in the view: formlog = auth_views.LoginView.as_view(template_name='main/index.html') (before return render...) to:
formlog = AuthenticationForm(request)
Take this line outside of the else block.
Also add the import for the form at the top of your views.py:
from django.contrib.auth.forms import AuthenticationForm
This change is required because the template needs the form object (which is AuthenticationForm for LoginView by default) instead of the view object. The updated view function will look like:
from django.contrib.auth.forms import AuthenticationForm
def index(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if 'signup' in request.POST:
if form.is_valid():
form.supervalid()
form.save()
username = form.cleaned_data.get('username')
messages.success(request, f'Dear {username} you have been created a new accound!')
return redirect('main')
elif 'login' in request.POST:
log_view = auth_views.LoginView.as_view(template_name='main/index.html')
log_view(request)
else:
form = UserRegisterForm()
formlog = AuthenticationForm(request)
return render(request, 'main/index.html', {'form': form, 'formlog': formlog})
Note that this can be improved by providing feedback when the login credentials are invalid. As it is, this updated code only reloads a blank login form if the provided credentials don't work.

Button not sending POST request to update object django

I have a scheduling app with Event objects and I'm trying to create a form that will allow the user to update an Event that already exists by the press of the button. However, when the user presses the button it doesn't seem to do anything. It just refreshes the page.
{% for a in availability %}
<form method='POST'>
<li><a class="btn btn-primary" href="{% url 'updateevent' a.id %}" type="submit" role="button">{{a.day}}: {{a.start_time}} - {{a.end_time}}</a></li>
</form>
{% endfor %}
view.py:
def updateevent(request, pk):
if request.method == 'POST':
try:
form = EventForm(data=request.POST, instance=post)
updatedEvent = form.save(commit=False)
updatedEvent.requester_user = request.user
updatedEvent.notes = None
updatedEvent.save()
return redirect('/')
except ValueError:
print(form.errors)
return render(request, 'events/createevent.html', {'form':EventForm(), 'error':'There was an error. Please make sure you entered everything correctly!'})
else:
return redirect('/')
I want the user that presses the button to become the "requester_user", a blank field in my Event object. How can I make this happen?
Anchor tag triggers GET request. You should use <button type="submit"></button> or <input type="submit"> for POST request.

Django checkout not accessible: Page not found (404)

I'm trying to develop an e-commerce site with Django. So I'm at this point where, users can add items to their cart, but when I try to proceed to checkout, for some reason, my checkout form is not displayed rather, it says:
Page not found (404)
I made sure that I have registered my models, and ran migrations.
What is the problem?
My views.py:
#login_required
def checkout(request):
address_form = UserAddressForm(request.POST or None)
if address_form.is_valid():
new_address = address_form.save(commit= False)
new_address.user = request.user
new_address.save()
else:
raise Http404
print(form.errors)
context = {"address_form": address_form}
template = "orders/checkout.html"
return render(request, template, context)
My checkout.html:
<form method="POST" action=''>
{% csrf_token %}
<fieldset class="form-group">
{{ address_form|crispy }}
</fieldset>
<div class="form-group">
<input type="submit" class="btn btn-outline-dark" value="Place Order"/>
</div>
</form>
My urls.py:
from orders import views as orders_views
path('checkout/', orders_views.checkout, name='checkout'),
You've implemented GET request handling incorrectly, for reference see this example from the docs. In your case form was always invalid because in case of GET request it was initialized with none. However you don't even have to validate empty form on GET request.
Your code updated:
#login_required
def checkout(request):
if request.method == 'POST':
address_form = UserAddressForm(request.POST)
if address_form.is_valid():
new_address = address_form.save(commit= False)
new_address.user = request.user
new_address.save()
return # TODO : return what?
else:
# otherwise (if GET request) we get here
address_form = UserAddressForm()
context = {"address_form": address_form}
return render(request, "orders/checkout.html", context)
And you need to specify what is supposed to happen when the form is valid: redirect for example.

Forbidden 403: CSRF token missing or incorrect

I keep getting this error when submitting a POST request with a form:
CSRF verification failed. Request aborted.
and then it says that the CSRF token missing or incorrect. I definitely included the token in my html, and here's my views method:
def create(request):
if request.method == 'POST':
form = TextForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/texts')
else:
form = TextForm()
return render_to_response('texts/index.html', {'form': form},
context_instance=RequestContext(request))
What am I doing wrong?? I've tried a bunch of different things but nothing is fixing it.
Here's the index.html:
<h1> Texts </h1>
<form action="/texts/create/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" name = "submit" value="Submit" />
</form>
<hr>

Categories

Resources