django form not posting, but other form on page does? - python

I have two forms on a page. The first form properly sends a POST request to my view but the second form sends a GET (I need it to also send a POST). I've made this mistake before and this time I made sure that the button is set to "submit", but for some reason it still sends a GET.
form 1 (working as intended):
<form method="POST">
{% csrf_token %}
<div class="row form-row">
<div class="col-sm-6">
<div class="form-group">
<label for="start_date">Start</label>
<input class="form-control" type="text" data-flatpickr data-alt-input="true" data-date-format="Y-m-d" name="start_date" data-enable-time="true">
</div>
<div class="form-group">
<label for="end_date">End</label>
<input class="form-control" type="text" data-flatpickr data-alt-input="true" data-date-format="Y-m-d" name="end_date" data-enable-time="true">
</div>
</div>
</div>
<input type="hidden" name="eventtype" value="availability">
<button class="btn btn-primary" type="submit">Save changes</button>
</form>
form 2 (sends a GET but I want this to POST):
<form method="POST">
{% csrf_token %}
{% if form.errors %}{{form.errors}}{% endif %}
<input type="hidden" name="pk" value="{{ i.id }}">
<input type="hidden" name="eventtype" value="invite">
<button class="btn btn-primary" type="submit">Confirm</button>
</form>
views.py
def createevent(request):
if request.method == 'GET':
<<code>>
else:
try:
eventtype = request.POST.get('eventtype', None)
print(eventtype)
if eventtype == "availability":
form = EventForm(request.POST)
newEvent = form.save(commit=False)
newEvent.mentor_user = request.user
newEvent.requester_user = None
newEvent.notes = None
newEvent.save()
elif eventtype == "invite":
form = EventForm(request.POST)
updatedEvent = form.save(commit=False)
updatedEvent.isConfirmed = True
updatedEvent.save()
return redirect('createevent')
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!'})
urls.py
# Events
path('events/create', views.createevent, name='createevent'),
# path('calendar/<slug:slug>', views.viewevent, name='viewevent'),
path('events/<int:pk>/edit', views.updateevent, name='updateevent'),
console output for form 1 and form 2:
"GET /events/create?csrfmiddlewaretoken=<<redacted>>&pk=2&eventtype=invite HTTP/1.1" 200 25560
"POST /events/create?csrfmiddlewaretoken=<<redacted>>&pk=2&eventtype=invite HTTP/1.1" 302 0

Set the action of form to your url path.
Look at this:
<form name="form" method="POST" action="{% url 'your_url_name' %}">

The issue ended up being the form was wrapped in another form tag further up in the template code. When I clicked the Submit button, the Submit button was firing on the first form and not the second. Just a bad copy/paste.

Related

Django request.POST.get() returns None

I face a problem and I can't find a solution.
I'm trying to redirect to the previous page after login. Somehow the ?next=request.path returns none when trying to request.POST.get() after submission.
This is my Html code that directs the user to the login page, taking the request.path as "next page after login" value.
{% if user.is_authenticated %}
<button class="btn" data-toggle="modal" data-target="#inquiryModal">
<a class="btn btn-primary border rounded-0"
role="button" href="#">Make an Inquiry</a>
</button>
{% else %}
<a class="btn btn-primary border rounded-0" role="button"
href="{% url 'login' %}?next={{ request.path|urlencode }}"
>Make An Inquiry</a>
{% endif %}
This is the login page html code.
<div class="login-clean" style="background-color: #fff;">
<form action="{% url 'login' %}" method="POST">
{% csrf_token %}
<!--- ALERTS -->
{% include 'partials/_alerts.html' %}
<div class="form-group">
<input class="form-control" type="email" name="email" placeholder="Email"></div>
<div class="form-group">
<input class="form-control" type="password" name="password" placeholder="Password">
</div>
<div class="form-group">
<button class="btn btn-primary btn-block" type="submit">Log In</button>
</div>
</form>
</div>
Views.py file
def login(request):
if request.method == 'POST':
email = request.POST['email']
password = request.POST['password']
valuenext = request.POST.get('next')
print(valuenext)
user = auth.authenticate(username=email, password=password)
# if user is found and not from listing page login and redirect to dashboard
if user is not None and valuenext == "":
auth.login(request, user)
messages.success(request, 'You are now succesfully logged in')
return redirect('dash_inquiries')
# if user is found and from specific listing page login and redirect to the listing
elif user is not None and valuenext != "":
auth.login(request, user)
print("success")
messages.success(request, 'You are now logged in')
return redirect(valuenext)
else:
messages.error(request, 'Invalid credentials')
return redirect('login')
else:
return render(request, 'accounts/login.html')
What am I doing wrong here? The next value is passed in the url when directing to the login page, but I don't seem to correctly get() the next value in my backend as it keeps returning None.
Thanks in advance.
Clicking on following button will send a GET request.
<a class="btn btn-primary border rounded-0" role="button"
href="{% url 'login' %}?next={{ request.path|urlencode }}">Make An Inquiry</a>
This get request will render accounts/login.html template.
You're parsing request.POST.get('next') for POST requests only. But there is no next in
<form action="{% url 'login' %}" method="POST">
You need your form tag to look like
<form action="{% url 'login' %}next={{ next }}" method="POST">
To solve above issue, you need to parse 'next' for request.GET, and add it to context for response.
if request.method == 'POST':
# handle POST
else:
next = request.GET.get('next', '')
context = {'next': next}
return render(request, 'accounts/login.html', context=context)
And then, add this next into form.action.
<form action="{% url 'login' %}next={{ next }}" method="POST">
Okay, so I didn't make sure I passed the next value into the login form, therefore the solution was to add a hidden input to get the next value in the request:
<input type="hidden" name="next" value="{{ request.GET.next }}" />

How i can use multiple forms in loop at once

I have problem with using multiple forms at once, tried with loop count in name but when i check correct options and then submit I get this error:
The browser (or proxy) sent a request that this server could not understand.
Code:
{%for tournament in tournament_query%}
<div class="body-main">
<div class ="body-select">
<form action="", method="POST">
<input type="radio" name="option" value="{{tournament.player_one}}"> {{tournament.player_one}}<br>
</form>
</div>
<div class ="body-selected">
<form action="", method="POST">
<input type="radio" name="option" value="{{tournament.player_two}}"> {{tournament.player_two}}<br>
</div>
<input type="submit" value="Submit">
</form>
</div>
{%endfor%}
my flask route =
#app.route("/news", methods=['POST', 'GET'])
#login_required
def news():
tournament_query = Walka.query.join(Walka.Tournament).filter_by(name = 'Das').all()
if request.method == "POST":
option = request.form['options']
return option
return render_template("news.html", tournament_query = tournament_query)
I want to get value from every one but I don't know how I can acquire it

CSRF verification failed. Request aborted. {% csrf_token %} in django python3 html

I am trying to do a log in in django/python.
I have this in my views.py:
#csrf_exempt
def Principal(request):
context = {}
if request.method != 'GET':
context = {
'title': '405 Method Not Allowed',
}
if request.user.is_authenticated():
logged_q = 'Logged in as '+ request.user.username
logged = True
else:
logged_q = 'Not logged in.'
logged = False
print (logged_q)
top_aparcamientos = Aparcamiento.objects.all()
#top_aparcamientos = Comentario.objects.all().order_by('-aparcamiento__id').unique()[:5]
pagina_list = Pagina.objects.all()
context['top_aparcamientos'] = top_aparcamientos
context['pagina_list'] = pagina_list
usuario = request.user.username
context = {
'usuario' : usuario,
'logged' : logged
}
return render_to_response('index.html', context
So, for do my template, I take the variable logged in my base.html like that:
{% if logged %}
<div class ="container_corner">
<div class="topright">
<span id="corner_message"><strong>Bienvenido,</strong>&nbsp<span class="oblicuo">{{usuario}}</span></span>
Salir</button><br>
</div>
</div> {% else %}
<form id="login_form" action="login/" method ="POST">
{% csrf_token %}
<label for="id_username"><span class="login_fields">Nick: </span></label> <input id="id_username" maxlength="254" name="username" type="text" />
<label for="id_password"><span class="login_fields">Contraseña: </span></label> <input id="id_password" name="password" type="password" />
<button type="submit">Login</button>
</form> {% endif %}
But it gives me this error when I try to log in:
Forbidden (403) CSRF verification failed. Request aborted. Help Reason given for failure: CSRF token missing or incorrect.
Do I need anymore {% csrf_token %}? Where?
Thank you!
Instead of {% csrf_token %}, you can probably use
<input type='hidden' name='csrfmiddlewaretoken' value='{{ csrf_token }}' />
Or you can also use {{ csrf_input }}.
<form action="login/" method="post">{{ csrf_input }}

Simple django POST not working

I have a form like this:
<form action="{% url "forum.posts" forum=forum.slug thread=thread.slug %}" method="POST">
{% csrf_token %}
<div class="form-group">
<textarea class="form-control" placeholder="Začni tipkati.."></textarea>
</div>
<input type="submit" class="btn btn-success" value="Pošlji odgovor">
</form>
views.py
'''
Display all posts in a thread or create a new post in a thread.
'''
def posts(request, forum, thread):
forum = Forum.objects.get(slug=forum)
thread = Thread.objects.get(slug=thread)
if request.method == "POST":
return HttpResponse('ok')
posts = thread.posts.all()
return render(request, 'forum/posts.html', {
'forum': forum,
'thread': thread,
'posts': posts
})
urls.py (relevant part):
# List all posts in a thread / Submit a post to a forum
url(r'^(?P<forum>[-\w]+)/(?P<thread>[-\w]+)/$', 'forum.views.posts', name='forum.posts'),
HTML output:
<form action="/forum/o-spletiscu/novatemaa/" method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="4PQWDsAfHyjrhUnYU5P9vVhtaY3vLPBU">
<div class="form-group">
<textarea name="post-body" class="form-control" placeholder="Začni tipkati.."></textarea>
</div>
<input type="submit" class="btn btn-success" value="Pošlji odgovor">
</form>
After I hit submit, I expect ok to be returned, instead page refreshes and nothing happens.
Normal GET requests are working though..
What am I missing?
Edit:
It's working when I use #csrf_exempt on posts method.
page refreshes and nothing happens
Problem with your action value. try to inspect it and find wither the url is correct or not.
OR
your form does not have any input with name property.
Try this:
<form action="{% url "forum.posts" forum=forum.slug thread=thread.slug %}" method="POST">
{% csrf_token %}
<div class="form-group">
<textarea class="form-control" placeholder="Začni tipkati.." name="something"></textarea>
</div>
<input type="submit" class="btn btn-success" value="Pošlji odgovor">
</form>

Flask receiving empty forms

I'm trying to get a simple form set up in Flask for my own education. I've got a login.html page with this form code:
<form action="{{ url_for('login') }}" method="post">
<div>
<label for="username">Username</label>
<div>
<input type="text" id="username" name="username" placeholder="Username">
</div>
</div>
<div>
<label for="password">Password</label>
<div>
<input type="password" id="password" name="password" placeholder="Password">
</div>
</div>
<div >
<input class="btn" type="submit">
</div>
</form>
I'm using code like the following to receive it, but Flask returns an empty request.form so I can't process it.
#app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
request.form['username']
...
I really don't want to learn another library (WTForms) right now, and I'm using bootstrap so that will add to the headache. What am I not seeing here with Flask/HTML?
I had this problem, but it was because I forgot to assign a name attribute to my input elements and I was trying to refer access the form data by the id attribute instead
i.e.
My HTML and Python was as shown below
HTML
<input type="text" id="usernameTxtBx">
Python
request.form['usernameTxtBx']
What I have done now:
HTML
<input type="text" name="username" id="usernameTxtBx">
Python
request.form['username']
I also needed to ensure that I was using a POST request. A GET request gave me an empty dictionary in my python code.
The OP made neither of these mistakes. But this may help someone that stumbles on this thread.
I had that problem.
Some tools like postman or some libraries or web browser sends the data in a way that flask does not identify as posted values. From my point of view this is a flask issue.
This is the workaround I followed to solve it:
1 - I sent the information using json. Have a look to this:
How to send a JSON object using html form data
2 - I instead of getting the parameters using:
value = request.form["myparamname"]
I used this:
json_data = request.get_json(force=True)
value = json_data["myparamname"]
just use request.get_json() in POST requests
login.html
{% extends "layout.html" %}
{% block content %}
<div class="form">
<h2>Sign In</h2>
{% for field in form.errors %}
{% for error in form.errors[field] %}
<div class="alert alert-error">
<strong>Oops...</strong> {{error}}.
</div>
{% endfor %}
{% endfor %}
<form action="{{ url_for('login') }}" method=post>
{{ form.hidden_tag() }}
{{ form.email.label }}
{{ form.email }}
{{ form.password.label }}
{{ form.password }}
<p> <input id="submit" name="submit" type="submit" class="btn btn-inverse" value="Sign In"></p>
</form>
</div>
{% endblock %}
forms.py
class SigninForm(Form):
email = TextField("email", [validators.Required("Please enter your email")])
password = PasswordField('Password', [validators.Required("Please enter a password.")])
submit = SubmitField("Sign In")
Then import the signinform in your views and create your login method like this
#app.route('/login', methods=['GET', 'POST'])
def signin():
form = SigninForm()
if form.validate_on_submit():
session['email'] = form.email.data
flash('You are logged in')
return redirect(url_for('dashboard'))
return render_template('signin.html', form=form)
Refer this tutorial for more detailed instructions
http://pypix.com/python/building-flask-blog-part-1/

Categories