I am inserting the data in database using Flask SQLAlchemy
Everything is going fine when I insert data using "/" in action attribute code but when I use to redirect to action="users.html" page after posting the data
I get the message "the method is not allowed for requested url in users page and data does not save too"
<form method="POST" action="/">
Name <input type="text" name="name">
<br>
Password <input type="text" name="email">
<br>
<input type="submit">
</form>
class Users(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
#app.route("/", methods = ['GET', 'POST'])
def contact():
if(request.method=='POST'):
'''Add entry to the database'''
name = request.form.get('name')
email = request.form.get('email')
entry = Users(name=name, email=email)
db.session.add(entry)
db.session.commit()
return render_template('index.html')
#app.route('/users')
def users():
return render_template('users.html')
Try adding methods=['POST'] to:
#app.route('/users', methods=['POST'])
def users():
return render_template('users.html')
Related
I can't make my code work. I've been looking around for tutorials and guides but to no avail. If anyone see the mistake I'm doing, it would be very helpful.
Here is the folder structure:
/
application.py
database.db
/routes
__init__.py
signup.py
/templates
signup.html
Here is my signup.py:
import sqlite3
from flask import Blueprint, render_template, redirect, session, request, flash
from werkzeug.exceptions import default_exceptions, HTTPException, InternalServerError
from werkzeug.security import check_password_hash, generate_password_hash
# Set Blueprints
signup = Blueprint('signup', __name__,)
#signup.route("/signup", methods=["GET", "POST"])
def signupFunction():
# Forget any user_id
session.clear()
# User reached route via POST (as by submitting a form via POST)
if request.method == "POST":
try:
email = request.form.get("email")
username = request.form.get("username")
password = request.form.get("password")
confirmPassword = request.form.get("confirm-password")
with sqlite3.connect("./database") as connection:
print("Opened database successfully")
current = connection.cursor()
# Ensure email was submitted
if not email:
return flash("must provide email")
# Ensure username was submitted
if not username:
return flash("must provide username")
# Ensure password was submitted
if not password:
return flash("must provide password")
# Ensure confirm password is correct
if password != confirmPassword:
return flash("The passwords don't match")
# Query database for username if already exists
current.execute("SELECT * FROM users WHERE username = :username", username=username)
if current.fetchall() == username:
return flash("Username already taken")
# Insert user and hash of the password into the table
current.execute("INSERT INTO users(username, hash) VALUES (:username, :hash)", username=username, hash=generate_password_hash(password))
current.commit()
# Query database for username
current.execute("SELECT * FROM users WHERE username = :username", username=username)
rows = current.fetchall()
# Remember which user has logged in
session["user_id"] = rows[0]["id"]
# Commit to databse
connection.commit()
print("Database operation succesful")
except:
connection.rollback()
print("Error in sign up operation")
finally:
# Close database connection
connection.close()
# Redirect user to home page
return redirect("/")
# User reached route via GET (as by clicking a link or via redirect)
else:
return render_template("signup.html")
here is my signup.html
{% extends "layout.html" %}
{% block title %}
Sign Up
{% endblock %}
{% block main %}
<p>Register or <a href='/signin'>login</a></p><br>
<form action="/signup" method="post">
<div>
<p>Username (6 characters min).</p>
<input id="username" autocomplete="off" autofocus class="form-control" name="username" placeholder="Username" type="text">
</div>
<br>
<div>
<p>Email.</p>
<input id="email" autocomplete="off" autofocus class="form-control" name="email" placeholder="Email" type="text">
</div>
<br>
<div>
<p>Password (7 to 15 characters, 1 numeric, 1 special).</p>
<input id="password" name="password" placeholder="Password" type="password">
</div>
<div>
<input id="confirm-pass" name="confirm-password" placeholder="Confirm Password" type="password">
</div>
<br>
<button id="submit" type="submit">Sign Up</button>
<br>
</form>
<script>
// Password must be between 7 to 15 characters which contain at least one numeric digit and a special character
document.querySelector("#submit").disabled = true;
document.querySelector("#confirm-pass").onkeyup = function() {
let password = document.querySelector("#password").value;
let username = document.querySelector("#username").value;
let email = document.querySelector("#email").value;
let confirmation = document.querySelector("#confirm-pass").value;
if (password.match(/^^(?=.*[0-9])(?=.*[!##$%^&*])[a-zA-Z0-9!##$%^&*]{7,15}$/i)) {
document.querySelector("#submit").disabled = true;
if (email.match(/^(([^<>()\[\]\.,;:\s#\"]+(\.[^<>()\[\]\.,;:\s#\"]+)*)|(\".+\"))#(([^<>()[\]\.,;:\s#\"]+\.)+[^<>()[\]\.,;:\s#\"]{2,})$/i)) {
document.querySelector("#submit").disabled = true;
if (username.length > 5) {
document.querySelector("#submit").disabled = true;
if (confirmation === password) {
document.querySelector("#submit").disabled = false;
}
}
}
}
else {
document.querySelector('#submit').disabled = true;
}
}
</script>
{% endblock %}
Here is the output of my console:
* Serving Flask app "application.py"
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [13/Dec/2020 19:23:44] "GET /signup HTTP/1.1" 200 -
127.0.0.1 - - [13/Dec/2020 19:23:44] "GET /static/styles.css HTTP/1.1" 200 -
Opened database successfully
Error in sign up operation
So the problem lies in signup.py
The try/except block is not doing you any favors. It can error on any line and all you'll know is "Error in signup operation". There will be problems because of invalid execute syntax. execute takes at most 2 arguments, the first is the sql to be executed. If it contains placeholders, the second argument is a set. Since these sqls are using named style, the second argument should be a dictionary, as per this example from the doc.
# And this is the named style:
cur.execute("select * from people where name_last=:who and age=:age", {"who": who, "age": age})
You might consider "catching" the exception and adding more info to the message, something like:
except Exception as e:
print("Error in sign up operation: ",e)
I'm new to python and Flask, I'm having an issue with updating a field entry, I can add 2 fields in a user profile and saves data to their user page, also I'm able to delete that entry, but when trying to update the "Tips" field, it comes back as a 'Bad Request' error; files are:
app.py:
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, PasswordField
from flask_sqlalchemy import SQLAlchemy
from forms import RegistrationForm, LoginForm, InstrumentForm, IdeasForm
from werkzeug.urls import url_parse
from werkzeug.security import generate_password_hash, check_password_hash
from wtforms import StringField, SubmitField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length
from flask_login import LoginManager, UserMixin, current_user, login_user, logout_user, login_required
from flask_bootstrap import Bootstrap
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///Mix_Tips.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config["TEMPLATES_AUTO_RELOAD"] = True
db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key= True)
username = db.Column(db.String(15), index =True, unique = True)
email = db.Column(db.String(150), index = True, unique = True)
password_hash = db.Column(db.String(200))
idea = db.relationship('Ideas', backref='author', lazy='dynamic')
def __repr__(self):
return '<User {}>'.format(self.username)
return '<N'
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password_hash(self, password):
return check_password_hash(self.password_hash, password)
class Tips(db.Model):
Instrument = db.Column(db.String(50), primary_key = True)
Frequency_Boost = db.Column(db.String(200), index =True, unique=True)
Frequency_Cut = db.Column(db.String(200), index =True, unique = True)
Advice = db.Column(db.String(500))
class Ideas(db.Model):
id = db.Column(db.Integer, primary_key = True)
Instrument = db.Column(db.String(50))
Tips = db.Column(db.String(200))
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return '<Tricks {}>'.format(self.Tips)
#app.route('/', methods=["GET", "POST"])
def login():
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user and user.check_password_hash(form.password.data):
login_user(user, remember=form.remember_me.data)
return redirect(url_for('user', username = form.username.data))
if user is None or not user.check_password_hash(form.password.data):
flash('Invalid username or password')
return render_template('login.html', form=form)
#app.route('/register', methods=["GET", "POST"])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
flash('Congratulations, you are now a registered user!')
return redirect(url_for('login'))
return render_template('register.html', title='Register', form=form)
#app.route('/user/<username>', methods=["GET", "POST"])
#login_required
def user(username):
user = current_user
user = User.query.filter_by(username=user.username).first()
idea = Ideas.query.filter_by(user_id=user.id)
if idea is None:
idea = []
form = IdeasForm()
if request.method == 'POST' and form.validate():
New_Idea = Ideas(Instrument = form.Instrument.data, Tips = form.Tips.data, user_id=current_user.id)
db.session.add(New_Idea)
db.session.commit()
print(request.form.get('Tips'))
return render_template('user.html', user=user, form=form, idea=idea)
#app.route('/update/<int:id>', methods=['POST', 'GET'])
def update(id):
tip_to_update = Ideas.query.get_or_404(id)
if request.method == 'POST':
tip_to_update.Tips = request.form['Tips']
db.session.commit()
return redirect(url_for('user', username=current_user))
else:
return render_template('update.html', tip_to_update=tip_to_update)
#app.route('/delete/<int:id>')
def delete(id):
idea_to_delete = Ideas.query.get_or_404(id)
try:
db.session.delete(idea_to_delete)
db.session.commit()
return redirect(url_for('user', username=current_user))
except:
return "Problem Deleting"
#login_manager.user_loader
def load_user(id):
return User.query.get(int(id))
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('login'))
**user.html:**
{% extends 'base.html' %}
{% block content %}
<center><h1 style="color:rgb(41, 15, 135)">Welcome back {{current_user.username }}!</h1></center>
<center><h2 style="color:rgb(41, 15, 135)">Music Mixing Guide</h2></center>
<h3 style="color:rgb(69, 67, 67)">Add your Instrument and Specific Tips for Mixing below:</h3>
<form action="user" method='POST'>
{{ form.hidden_tag() }}
<p
style="color:rgb(52, 52, 52)">{{form.Instrument.label}} <br>
{{form.Instrument(size=30)}}
</p>
<p
style="color:rgb(52, 52, 52)">{{form.Tips.label}} <br>
{{form.Tips(size=80)}}
</p>
<p> <input class="btn btn-outline-dark" type="submit" value="Add"></p>
</form>
<br>
<h3>Your Music Mixing Tips</h3>
{% for tricks in idea %}
<ol>
<li><p style="color:rgb(41, 15, 135)"> <b><h5>Instrument:</h5></b> {{tricks.Instrument}}</li>
<p style="color:rgb(41, 15, 135)"> <b><h5>Tip:</h5></b> {{tricks.Tips}}
</ol>
<p></p> Update
Delete
<br>
{% endfor %}
<br>
<br>
<br>
Log Out
{% endblock %}
**update.html:**
{% extends 'base.html' %}
{% block content %}
<div class='container'></div>
<h2>Update Mix Tip</h2>
<br>
<form action="/update/{{tip_to_update.id}}" method="POST">
<input type="text" placeholder="Tip" Tips="Tips" class="form-control" value="{{tip_to_update.Tips}}"> <br> <br>
<input type="submit" value="Update" class="btn btn-secondary btn-sm">
</form>
</div>
{% endblock %}
**forms.py**
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField, SelectField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo, Length
from flask_sqlalchemy import SQLAlchemy
class RegistrationForm(FlaskForm):
username=StringField('Username', validators=[DataRequired(), Length(min=4, max=15)])
email=StringField('Email', validators=[DataRequired(), Email(message='Invalid Email'), Length(max=150)])
password=PasswordField('Password', validators=[DataRequired(), Length(min=4, max=150)])
Repeat_password=PasswordField('Repeat Password', validators=[DataRequired(), EqualTo('password')])
submit=SubmitField('Register')
class LoginForm(FlaskForm):
username=StringField('Username', validators=[DataRequired(), Length(min=4, max=15)])
password=PasswordField('Password', validators=[DataRequired(), Length(min=4, max=150)])
remember_me=BooleanField('Remember Me')
submit=SubmitField('Sign In')
class InstrumentForm(FlaskForm):
Instrument= SelectField('Instrument', choices=[('Voice'), ('Acoustic Guitar'), ('Electric Guitar'),
('Bass Guitar'), ('Piano'), ('Bass Drum'), ('Snare Drum'), ('HiHats'), ('Toms'), ('Cymbals'), ('Brass')])
class IdeasForm(FlaskForm):
Instrument = StringField('Instrument')
Tips = StringField('Tips')
submit= SubmitField('Add')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user is not None:
raise ValidationError('Please use a different username.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user is not None:
raise ValidationError('Please use a different email address.')
I think it may have something to do with the "request.form['Tips'] line in app.py, but would like to know for sure and how to fix it.
Thanks
welcome mac. I'm not sure the error message, but as far as i can tell you'll need to rework your database models, your relationships to be precised. Here is an example:
class Ideas(db.Model):
id = db.Column(db.Integer, primary_key = True)
instrument = db.Column(db.String(50))
tips = db.relationship("Tips", lazy="dynamic")
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
have a look at the docs: https://flask-sqlalchemy.palletsprojects.com/en/2.x/models/
also i recomment this flask mega tutorial from Miguel Grinberg: https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
Thanks for the advice , I finally found out what was wrong , the "tip_to_update.Tips = request.form['Tips']" line in the update route should be "tip_to_update.Tips = form.Tips.data" instead , as I used the Flask Form method of collecting data in my register route, it wasn't accepting the request.form method. I'm still unable to show the data entered in the placeholder when a user wants to update a Tip, it opens the update page with a empty placeholder field to update , but I'd like the text from the entered tip to show , so the user can make a few alterations instead of typing out the whole tip again.
here is my "forms.py"
class CreateUser(UserCreationForm):
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
and here is my "views.py"
def register(request):
form = CreateUser()
if request.method == 'POST':
form = CreateUser(request.POST)
if form.is_valid():
form.save()
# messages.sucess(request, 'Acccount created!')
return redirect('login')
context = {'form':form}
return render(request, 'register.html', context)
and here is my basic register.html so far.
<h3>Register</h3>
<form method="POST" action="">
{% csrf_token %}
{{form.as_p}}
<input type="submit" name="Create User">
I already have a user!
{{form.errors}}
</form>
The thing is, I need to add a lot of stuff to the registration. The default user/password login is ideal, but the registration needs to have other fields for things like address and credit card number. How do I properly extend this registration, in a way that the login is still the same?
I don't know if it is the best way or similar, so I'm not sure about using Usercreationform, but I did it in my projects like this. I created a User model in my models.py, and then I just defined the fields I needed for the registerform before the meta class in the forms.py
class RegisterForm(forms.ModelForm):
username = forms.CharField(max_length=30)
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
email = forms.EmailField(max_length=254)
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ['username', 'first_name', 'last_name', 'email', 'password']
I have a one-to-many relationship created but I am not sure how I can post the organization that has been selected from the dropdown menu with the new site details that have been created.
Basic page layout will be dropdown containing organization names that have already been created and stored in the organization table in the db. End-user selects an organization then types in the new name for a site and clicks submit.
Code is below and any help will be most appreciated.
App.py
#app.route('/add_site')
def add_site():
""" Find and show field from db for the user to fill in """
form = AddSite()
organisations = db.session.query(Organisation)
return render_template('add_site.html', form=form,
organisations=organisations)
#app.route('/insert_site', methods=['GET', 'POST'])
def insert_site():
""" Insert populated fills from add_site to db """
form = AddSite()
site_name = Site(site_name=form.site_name.data)
db.session.add(site_name)
db.session.commit()
return redirect(url_for('get_org'))
forms.py
class AddSite(FlaskForm):
""" Adding new site """
site_name = StringField('Site Name', validators=[DataRequired()])
submit = SubmitField('Add Site')
Models.py
class Organisation(db.Model):
""" Table to store organisation details """
id = db.Column(db.Integer, primary_key=True, index=True,
unique=True)
org_name = db.Column(db.String())
timestamp = db.Column(db.DateTime, index=True,
default=datetime.utcnow)
sites = db.relationship('Site', backref='org_name', lazy='dynamic')
def __init__(self, org_name):
self.org_name = org_name
class Site(db.Model):
""" Table to store site details """
id = db.Column(db.Integer, primary_key=True)
site_name = db.Column(db.String())
timestamp = db.Column(db.DateTime, index=True,
default=datetime.utcnow)
org_id = db.Column(db.Integer, db.ForeignKey('organisation.id'))
def __init__(self, site_name):
self.site_name = site_name
add_site.html
<form action=" {{url_for('insert_site') }}" method="POST" class="col-12">
{{ form.hidden_tag() }}
<div class="col s12">
<select name="organisation_list">
<option value="" disabled selected>Choose an
Organisation</option>
{% for org in organisations %}
<option value ="{{org.org_name}}">{{org.org_name}}</option>
{% endfor %}
</select>
<label>Organisations</label>
</div>
<div class="row">
<div class="col s12">
{{ form.site_name.label }}
{{ form.site_name(size=32) }}
</div>
</div>
<div class="row">
<buttom>
{{ form.submit() }}
</buttom>
</div>
</form>
The end result is to map multiple sites to a organization. This is so I can create a page which will show all the sites that are under an organization.
Try this in your scripts
App.py
from flask import (request, render_template, redirect_url,
url_for)
from app.Models import db, Site # Use proper import here for your app
#app.route('/add_site', methods=['GET', 'POST'])
def add_site():
form = AddSite(request.form)
if request.method == 'POST' and form.validate():
site = Site(
site_name=form.site_name.data,
org_id=form.organisation.data
)
db.session.add(site)
db.session.commit()
return redirect(url_for('get_org'))
return render_template('add_site.html', form=form)
forms.py
from flask_wtf import FlaskForm as Form
from wtforms import (SelectField, StringField, SubmitField)
from wtforms.validators import DataRequired as Required
from app.Models import Organisation # Use proper import here for your app
class AddSite(Form):
""" Adding new site """
site_name = StringField('Site Name',
validators=[Required('Site name is required')])
organisation = SelectField('Organisation', coerce=int,
validators=[
Required('Please select an organisation')])
submit = SubmitField('Add Site')
def __init__(self, *args, **kwargs):
super(AddSite, self).__init__(*args, **kwargs)
organisations = Organisation.query.with_entities(
Organisation.id, Organisation.org_name). \
order_by(Organisation.org_name).all()
self.organisation.choices = [
(organisation.id, organisation.org_name)
for organisation in organisations
]
Models.py
class Organisation(db.Model):
""" Table to store organisation details """
__tablename__ = 'organisation'
id = db.Column(db.Integer, primary_key=True)
org_name = db.Column(db.String(100))
timestamp = db.Column(db.DateTime, index=True,
default=datetime.utcnow)
sites = db.relationship('Site', backref='organisation', lazy='dynamic')
def __repr__(self):
return '<Organisation: {!r}'.format(self.org_name)
class Site(db.Model):
""" Table to store site details """
__tablename__ = 'site'
id = db.Column(db.Integer, primary_key=True)
site_name = db.Column(db.String())
timestamp = db.Column(db.DateTime, index=True,
default=datetime.utcnow)
org_id = db.Column(db.Integer, db.ForeignKey('organisation.id'))
def __repr__(self):
return '<Site: {!r}'.format(self.site_name)
add_site.html
<form action=" {{url_for('add_site') }}" method="POST">
<div class="form-group{% if form.site_name.errors %} has-error{% endif %}">
{{ form.site_name.label(for_='site_name') }}
{{ form.site_name(class='form-control') }}
{% if form.site_name.errors %}
<span class="help-block">{{ form.site_name.errors[0] }}</span>
{% endif %}
</div>
<div class="form-group{% if form.organisation.errors %} has-error{% endif %}">
{{ form.organisation.label }}
{{ form.organisation(class='form-control') }}
</div>
{{ form.csrf_token }}
{{ form.submit(class='btn btn-default', value='Add Site') }}
</form>
i´m doing a simple project where I want to add jwt authentication.
When I log in I try to create a new token but when i´m trying to see who´s the user using the token it says that the token is missing.
I´m using Flask and SQLAlchemy with Postgresql
app.py
app.config['JWT_TOKEN_LOCATION'] = ['cookies']
#app.config['JWT_COOKIE_SECURE'] = False
app.config['JWT_ACCESS_COOKIE_PATH'] = '/api/'
app.config['JWT_REFRESH_COOKIE_PATH'] = '/token/refresh'
app.config['JWT_COOKIE_CSRF_PROTECT'] = False
app.config['JWT_SECRET_KEY'] = 'abva'
jwt = JWTManager(app)
#app.route('/token/auth', methods=['POST'])
def login():
email = request.form['email']
password = request.form['password']
user = User.query.all()
for user in user:
if user.email == email and user.password == password:
access_token = create_access_token(identity=user.email)
refresh_token = create_refresh_token(identity=user.email)
# Set the JWTs and the CSRF double submit protection cookies
# in this response
resp = jsonify({'login': True})
set_access_cookies(resp, access_token)
set_refresh_cookies(resp, refresh_token)
return resp, 200
return jsonify({'login': False}), 401
#app.route('/protected', methods=['GET'])
#jwt_required
def protected():
ret = {
'current_identity': get_jwt_identity(), # test
}
return jsonify(ret), 200
#app.route('/token/remove', methods=['POST'])
def logout():
resp = jsonify({'logout': True})
unset_jwt_cookies(resp)
return resp, 200
#jwt.user_identity_loader
def user_identity_lookup(user):
return user
add_user.html
<!DOCTYPE html>
<html>
<body>
<form method="POST" action="/token/auth">
<label> Email: </label>
<input id="email" name ="email" type="text" />
<label> Password: </label>
<input id="password" name ="password" type="password" />
<input type="submit" />
</form>
<form method="POST" action="/token/remove">
<input type="submit" value="LogOut" />
</form>
</body>
</html>
Your route is /protected but your JWT_ACCESS_COOKIE_PATH is /api/. That will prevent the cookie from being sent to that endpoint. Either change the endpoint to /api/protected, or change the cookie path to just /