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/
Related
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.
I want the user to be able to add or remove fields in the website, I am using flask and fields.FieldList
I know how to do that directly with javascript only clone the field section of the DOM and rename the attributes like name, id etc... is there an easy way to do it with flask/ flask forms? I want to achieve something like in the picture (doesn't have to be in that layout, I really don't care the layout since I can move it later on)
and then been able to pass it to the back end and been recognize by the flask forms.
thanks in advance, I appreciate it =)
This are my forms:
class AddressForm(FlaskForm):
addr = fields.StringField("address")
class MainForm(FlaskForm):
addressees = fields.FieldList(fields.FormField(AddressForm), min_entries=1, validators=[DataRequired()])
This is my view:
def addressees_create():
if request.method == 'POST':
form = MainForm()
if form.validate():
print("is validate")
else:
print("was not validate")
if form.validate_on_submit():
print("the form was validated on submit")
else:
print("was not validated on submit")
print(form.data)
addressees = form.data["addressees"]
for address in addressees:
print("\t"+str(address))
return render_template("my/template.html",form=form)
else:
form = MainForm()
return render_template("my/template.html", form=form)
This is the template:
<div>
{% for item in form.addressees %}
{{ item.hidden_tag() }}
{{ item.addr }}
{% endfor %}
<div style="color: red;">
{% for error in form.addressees.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
</div>
I also had this problem. Here is my solution
class CreatePollForm(FlaskForm):
title = StringField('Title', validators=[DataRequired()])
options = FieldList(StringField())
submit = SubmitField('Create')
<ul id="options">
<li>
<label for="options-0">Options-0</label>
<input id="options-0" name="options-0" type="text" value="">
</li>
<li>
<label for="options-1">
Options-1
</label>
<input id="options-1" name="options-1" type="text" value="">
</li>
<li>
<label for="options-2">Options-2</label>
<input id="options-2" name="options-2" type="text" value="">
</li>
<li>
<label for="options-3">Options-3</label>
<input id="options-3" name="options-3" type="text" value="">
</li>
<li>
<label for="options-4">Options-4</label>
<input id="options-4" name="options-4" type="text" value="">
</li>
</ul>
You can refer to this data like this:
form = CreatePollForm()
print(form.options.data)
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
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> <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 }}
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>