I am trying to create a page to register users but the submit button in my bootstrap form isn't working. When I hit the submit button, I get a bad request error. Here is the code in my python file:
#app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
if not request.form['username']:
error = 'You have to enter a username'
elif not request.form['email'] or '#' not in request.form['email']:
error = 'You have to enter a valid email address'
elif not request.form['password']:
error = 'You have to enter a password'
elif get_user_id(request.form['username']) is not None:
error = 'The username is already taken'
else:
print(request.form['username'])
db = get_db()
db.execute('INSERT INTO user (username, email, pw_hash) VALUES (?, ?, ?)',
[request.form['username'], request.form['email'],
generate_password_hash(request.form['password'])])
db.commit()
flash('You were successfully registered and can login now')
return render_template('control.html')
return render_template('register.html')
also i have a html file register.html:
{% extends 'layout.html' %}
{% block title %}Sign-up{% endblock title %}
{% block body %}
<div class="container">
<form class="form-register" role="form" method="post" action="{{ url_for('register') }}">
<h2 class="form-register-heading">Please sign up</h2>
<label for="username" class="sr-only">Username</label>
<input type="username" id="inputUsername" class="form-control" value="{{ request.form.username }}" placeholder="Username" required autofocus>
<label for="email" class="sr-only">Email address</label>
<input type="email" id="inputEmail" class="form-control" value="{{ request.form.email }}" placeholder="Email address" required autofocus>
<label for="password" class="sr-only">Password</label>
<input type="password" id="inputPassword" class="form-control" placeholder="Password" required >
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign up</button>
</form>
</div>
{% endblock body %}
I can't find where I did it wrong, I'm new to python and flask!
Your input fields have no name attribute. This will cause all of your checks to result in KeyErrors. The first step is to add the attribute to each input.
<input name="username" type="text" id="inputUsername" class="form-control" value="{{ request.form.username }}" placeholder="Username" required autofocus>
Note that I also checked the type attribute as there is no username type. email and password are valid values, email being added in HTML5.
The next step will be to change how you check for the fields. If you only care about the presence of the field, in is the way to go.
if 'username' not in request.form:
If, however, you also want a truty value, the get method is what you want.
if not request.form.get('username'):
Related
I have got a problem while redirecting to the edit form.
SO what I am doing is that whenever user clicks on edit button it redirects to "editadmin/{{admin.id}}" using form action = "editadmin/{{admin.id}}" in HTML.
URL path is
path("editadmin/<int:id>", views.editadmin, name="editadmin")
path("update/<int:id>", views.updateadmin, name="updateadmin")
Views.py
#csrf_exempt
def editadmin(request, id):
admin = Admin.objects.get(id=id)
return render(request, "editadmin.html", {"admin": admin})
#csrf_exempt
def updateadmin(request, id):
if request.method == "POST":
admin_id = request.POST["admin_id"]
admin_id = str(admin_id).strip().upper()
name = request.POST["name"]
name = str(name).strip()
if db_name equals to name:
messages.error(request, "Admin name already exists")
return redirect("editadmin/" + str(id))
editadmin.html
<form method="post" class="post-form" action="/update/{{admin.id}}">
<input type="hidden" name="id" id="id" required maxlength="20" value="{{ admin.id }}"/>
{% csrf_token %}
<div class="form-group row">
<label class="col-sm-3 col-form-label"><h4 style="margin-left:40px">Admin ID : </h4></label>
<div class="col-sm-4">
<input type="text" name="admin_id" required style="margin-left:20px; height:38px; width:300px;
border-radius: 5px" id="admin_id" value="{{ admin.admin_id }}"/>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3 col-form-label"><h4 style="margin-left:40px">Name : </h4></label>
<div class="col-sm-4">
<input type="text" name="name" style="margin-left:20px; height:38px;
border-radius: 5px; width:300px" required id="name" value="{{ admin.name }}"/>
</div>
</div>
<div class="form-group row">
<label class="col-sm-1 col-form-label"></label>
<div class="col-sm-4">
<button type="submit" class="btn btn-success" style="margin-left:210px">Submit</button>
</div>
</div>
So what I want is that Whenever user submits invalid name in editadmin.html (URL - editadmin/1 ), it should redirect to the same URL editadmin/1 but what it does is it appends update/ which redirects to update/editadmin/1
How to fix this? I dont want update/ to get appended after redirecting to same form.
update/ is appending because you mentioned your form action to this URL. So instead of mentioning action in your form, you can do something like this.
#csrf_exempt
def updateadmin(request, id):
if request.method == "POST":
admin_id = request.POST["admin_id"]
admin_id = str(admin_id).strip().upper()
name = request.POST["name"]
name = str(name).strip()
# asuming you are checking if admin with this name already exists in database
if db_name equals to name:
messages.error(request, "Admin name already exists")
return redirect("editadmin/" + str(id))
# It mean user enter a unique name
else:
# your logic to save the incoming user here.
message.success(request, "Your success message")
return redirect(f'/update/{admin_id}')
and make sure to update your form from this:
<form method="post" class="post-form" action="/update/{{admin.id}}">
to this:
<form method="post" class="post-form" action="">
I have a defined route in my Python Flask app(which worked fine).
#app.route('/insertpage', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
companyname = request.form['companyname']
username = request.form['username']
userpass = request.form['password']
new_company= Grocery(companyname=companyname,
username=username, userpass=userpass)
try:
db.session.add(new_company)
db.session.commit()
return render_template('index.html', data=Todos.query.all())
except:
return "The problem occurred while adding a new company...."
else:
groceries = Grocery.query.order_by(Grocery.created_at).all()
return render_template('index.html', groceries=groceries)
And I am collecting information in my HTML page:
<form action="/" method="POST">
<div class="form-row">
<div class="col-sm-3 my-1">
<label for="newStuff" class="sr-only">New company:</label>
<input type="text" class="form-control" name="companyname" id="newStuff" placeholder="Enter name of new company">
</div>
<div class="col-sm-3 my-1">
<label for="newStuff" class="sr-only">New username:</label>
<input type="text" class="form-control" name="username" id="newStuff" placeholder="Enter username...">
</div>
<div class="col-sm-3 my-1">
<label for="newStuff" class="sr-only">New password:</label>
<input type="text" class="form-control" name="password" id="newStuff" placeholder="Enter password...">
</div>
<div class="col-sm-3 my-1">
<button type="submit" class="btn btn-primary btn-block">Add</button>
</div>
</div>
</form>
After a couple of successful CRUD operations, I am facing the following error(even if I defined 'POST' and 'GET' in my def).
Method Not Allowed
The method is not allowed for the requested URL.
The action attribute of your HTML form needs to match the name of your Flask route.
Your page is sending a POST to url '/' , so it isn't hitting your route, which is for the path '/insertpage'
You should change it to <form action="/insertpage" method="POST">
When a new user signs up for an account, the admin panel shows that a password has not been set for the user (despite saving it via views.py). Another strange thing I noticed is that the password is being saved to the email field in the database. The code appears fine. Not sure where I went wrong. Any help would be greatly appreciated.
sign up html template
{% if user.is_authenticated %}
<h2>currently logged in as {{ user.username }} </h2>
{% else %}
<h1 class="h5 text-center">Create Account</h1>
<h4>{{ error }}</h4>
<form method="POST">
{% csrf_token %}
<div class="form-group">
<label for="username">Username</label>
<input type="text" class="form-control" name="username" autocomplete="username" placeholder="Username" id="id_username" required>
</div>
<div class="form-group">
<label for="password1">Password</label>
<input type="password" class="form-control" name="password1" placeholder="Password" autocomplete="new-password" required id="id_password1">
<small>Password must be at least 8 characters</small>
</div>
<div class="form-group">
<label for="password2">Confirm Password</label>
<input type="password" class="form-control" name="password2" placeholder="Confirm Password" autocomplete="new-password" required id="id_password2">
</div>
<ul>
<li>Your password can’t be too similar to your other personal information.</li>
<li>Your password must contain at least 8 characters.</li>
<li>Your password can’t be a commonly used password.</li>
<li>Your password can’t be entirely numeric.</li>
</ul>
<!-- <div class="form-group">
<div class="custom-control custom-checkbox text-small">
<input type="checkbox" class="custom-control-input" id="sign-up-agree">
<label class="custom-control-label" for="sign-up-agree">I agree to the <a target="_blank" href="utility-legal-terms.html">Terms & Conditions</a>
</label>
</div>
</div> -->
<button class="btn btn-primary btn-block" type="submit">Create Account</button>
</form>
views.py
def signup(request):
if request.method == 'GET':
return render(request, 'events/signup.html', {'form': UserCreationForm()})
else:
# Create new user and profile
if request.POST['password1'] == request.POST['password2']:
try:
print(request.POST['password1'])
print(request.POST['password2'])
user = User.objects.create_user(request.POST['username'], request.POST['password1'])
user.save()
login(request, user)
return redirect('home')
except IntegrityError:
return render(request, 'events/signup.html', {'form': UserCreationForm(), 'error':'Username has already been taken. Please use a different name.'})
else:
# Tell the user the passwords don't match
return render(request, 'events/signup.html', {'form': UserCreationForm(), 'error':'Passwords did not match'})
There's no mention of "email" anywhere in the code but for some reason the password gets saved as email and the actual password isn't getting set.
You need to set password explicitly, or send it in the third param, second param of create_user method is email, thats why password is being set as email.
reference to set_password method
reference to create_user method
You need something like this.
user = User.objects.create_user(username=request.POST['username'])
user.set_password('new password')
user.save()
Your code:
user = User.objects.create_user(request.POST['username'], request.POST['password1'])
user.save()
See the the docs:
create_user(username, email=None, password=None, **extra_fields)
So, oops, you send the password as second argument and it is interpreted as being the email address.
create_user(username=request.POST['username'], password=request.POST['password1'])
Should work.
I created a password reset system through email using django, but when I am at the password page, if I enter the password and confirmation right, it doesn't do anything just reloads the page and seems to throw in error in form.errors, but it shows this field is required (error) even though I filled it out.
In addition, how do you make it so only one email can be assigned to a user. So when registering or changing your info, the same email can't be used with two accounts.
Here is the code to my password reset page:
{% extends 'base.html' %}
{% block head %}
<link href="\static\accounts\css\forms.css" rel="stylesheet">
<script src="\static\registration\js\emailvariable.js"></script>
{% endblock %}
{% block body %}
{% if validlink %}
<h3 style="text-align: center">Change password</h3>
<form id="login-form" method="post">
{% csrf_token %}
<input placeholder="Password" id="id_password" name="password"
type="password" class="form-control">
<input placeholder="Confirm Password" id="id_password2" name="password2"
type="password" class="form-control">
<div style="text-align:center;">
<button type="submit" class="btn btn-outline-dark centerbutton">Change password</button>
</div>
{% if form.errors %}
<p class=" label label-danger">
<div style="text-align: center">
{{ error | escape }}
</div>
</p>
{% endif %}
</form>
{% else %}
<p>
The password reset link was invalid, possibly because it has already been used.
Please request a new password reset.
</p>
{% endif %}
{% endblock %}
I am not sure about your first question, but I can answer the 2nd.
class SignUpForm(UserCreationForm):
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(username=username).exists():
raise forms.ValidationError(u'Email addresses must be unique.')
return email
Put something like that in the forms.py where you have the registration form.
for the email portion of your question:
views.py
email = self.cleaned_data.get('email')
foo = User.objects.filter(email=email)
if foo:
return error
else:
***carry forth with saving the new user***
the 'if foo' will see if a user exists in the db with the email address given. If so, return error. If not carry forth with code.
I solved the form problem.
You need to change:
<input placeholder="Password" id="id_password" name="password" type="password" class="form-control">
<input placeholder="Confirm Password" id="id_password2" name="password2" type="password" class="form-control">
To this:
<input placeholder="Password" name="new_password1" required id="id_new_password1" type="password" class="form-control">
<input placeholder="Confirm Password" name="new_password2" required id="id_new_password2"
type="password" class="form-control">
What is happening is that your name entries are wrong, which causes the form to fail validation in general in the default password reset view and get returned with a generic error.
Just swap those out and the form should work fine.
I have a list of articles.
After I press Edit, I am redirected to another page containing in the url the id of the article that wants to be edited.
Edit
This is where I am redirected:
And I want the inputs to be filled with the title and the body text of the respective article.
This is my backend function:
#app.route('/edit_article/<string:id>', methods=['POST', 'GET'])
def edit_article(id):
conn = mysql.connect()
cursor = conn.cursor()
result = cursor.execute("SELECT * from articles where id=%s", [id])
data = cursor.fetchone()
if result < 0:
flash("Article does not exist!")
cursor.close()
conn.close()
return render_template("edit_article.html", data=data)
How can I use data to fill those inputs? Please help. Thank you.
I will put also the edit_article.html
{% extends 'layout.html' %}
{% block body %}
<div class="container">
<div class="jumbotron">
<h1>Bucket List App</h1>
<form class="form-addArticle">
<label for="inputTitle" class="sr-only">Title</label>
<input type="name" name="inputTitle" id="inputTitle" class="form-control" placeholder="Title" required autofocus>
<label for="inputBody" class="sr-only">Body</label>
<input type="text" name="inputBody" id="inputBody" class="form-control" placeholder="Body" required autofocus>
<button id="btnEditArticle" class="btn btn-lg btn-primary" type="button">Update article</button>
</form>
<p class="text-center" style="color:red" id="message"></p>
</div>
</div>
{% endblock %}
You can just need to add value="{{ ... }}" to your inputs:
<input type="name" value="{{ data[0] }}" name="inputTitle" id="inputTitle" class="form-control" placeholder="Title" required autofocus>
<input type="text" value="{{ data[1] }}" name="inputBody" id="inputBody" class="form-control" placeholder="Body" required autofocus>
But it's recommended to name the values:
name, text = cursor.fetchone()
return render_template("edit_article.html", name=name, text=text)
and then
<input type="name" value="{{ name }}" name="inputTitle" id="inputTitle" class="form-control" placeholder="Title" required autofocus>
<input type="text" value="{{ text }}" name="inputBody" id="inputBody" class="form-control" placeholder="Body" required autofocus>
But I'd personally recommend WTForms module instead of rendering forms manually - it can for example help to validate your inputs properly.