sqlalchemy.exc.IntegrityError: UNIQUE constraint failed - python

sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: user.city
[SQL: INSERT INTO user (username, "accountName", city, email, avatar, password) VALUES (?, ?, ?, ?, ?, ?)]
[parameters: ('sunny123', 'sunny kumar', 'Tumkur', 'sunny#gmail.com', 'default.jpg', '$2b$12$n3eEOEBhJ7aVEA4wctQn4O37jEYdgI0N2jqhNKm7Giy7Y7hxwaZIS')]
(Background on this error at: http://sqlalche.me/e/gkpj)
My User Model is
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key = True)
username = db.Column(db.String(20), unique = True, nullable = False)
accountName = db.Column(db.String(20), nullable = False)
city = db.Column(db.String(20), nullable = False)
email = db.Column(db.String(120), unique = True, nullable = False)
avatar = db.Column(db.String(20), nullable = False, default = 'default.jpg')
password = db.Column(db.String(60), nullable = False)
def __repr__(self):
return f"User('{self.username}', '{self.accountName}','{self.city}','{self.email}', '{self.avatar}')"`enter code here`
And My Route is
#app.route('/signup', methods = ['GET', 'POST'])
def signup():
if current_user.is_authenticated:
return redirect(url_for('home'))
form = SignUp()
if form.validate_on_submit():
hashed_password = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user = User(username = form.username.data, accountName = form.accountName.data, city = form.city.data, email = form.email.data, password = hashed_password)
db.session.add(user)
db.session.commit()
flash('Your account has been created, now you can Signin', 'success')
return redirect(url_for('signin'))
return render_template('signup.html', title = 'Sign Up', form = form)
whenever i am trying to add a user with city name eg: "abc" which is mentioned by a previous user then it is throwing an error, but in my User model unique = True is just for username.

SQLAlchemy as a library can be easily used for managing tables, even creating them, but only for once.
If you have had a unique city column previously, and you haven't changed it from the Database, it will keep reinforcing the unique constraint on the column.
Because for the database, it still has a unique constraint. You cannot remove the UNIQUE constraint using ALTER in SQLite.
Refer to this answer for recreating the database safely.

Related

Flask-sqlalchemy table user has no column named email_address

I am learning Flask and I am trying to add a user to my database and I get this error.
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) table user has no column named email_address
[SQL: INSERT INTO user (username, email_address, password_hash, budget) VALUES (?, ?, ?, ?)]
class User(db.Model):
id = db.Column(db.Integer(), primary_key=True)
username = db.Column(db.String(length=30), nullable=False, unique=True)
email_address = db.Column(db.String(length=50), nullable=False, unique=True)
password_hash = db.Column(db.String(length=60), nullable=False)
budget = db.Column(db.Integer(), nullable=False, default=1000)
items = db.relationship("Item", backref="owned_user", lazy=True)
This is my model.
class RegisterForm(FlaskForm):
username = StringField(label="Username:")
email_address = StringField(label="Email:")
password1 = PasswordField(label="Password:")
password2 = PasswordField(label="Confirm Pasword:")
submit = SubmitField(label="Create Account")
This is the form.
user_to_create = User(username=form.username.data,
email_address=form.email_address.data,
password_hash=form.password1.data)
db.session.add(user_to_create)
db.session.commit()
This is the part I create the user.
I guess I changed the name of the column at some point after I created the table. After deleting and recreating the table it fixed.

Why SQLAlchemy send null value for id primary column?

I'm trying to build an user registration page and facing this:
For some reason sqlalchemy forms this row for postgresql database - (null, roman, 2021-05-04), but I've passed in User model that id column is primary key (so NOT NULL)
I created tables in database via pgAdmin4
I have no idea why this is happening, because I used the same code but for MySQL and for SQLite and it works
models.py
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
registration_date = db.Column(db.DateTime, nullable=False)
def __init__(self, username, registration_date):
self.username = username
self.registration_date = registration_date
routes.py
#app.route('/register', methods=['POST', 'GET'])
def register():
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data,
registration_date=datetime.now(),
)
db.session.add(user)
db.session.commit()
flash('User was created!', 'success')
return redirect(url_for('login'))
return render_template('register.html', form=form)
The column is type INTEGER and PRIMARY_KEY but doesn't have any default value, so when trying to insert a row there with null value you'll get the error.
How is the table defined on postgreSQL? I suggest to use the identity as written here
create table t2 (id integer primary key generated always as identity);
The structure of the table is not what SQLAlchemy expects for your model. If we let SQLAlchemy create the table it will be
CREATE TABLE users (
id SERIAL NOT NULL,
username VARCHAR(20) NOT NULL,
registration_date TIMESTAMP WITHOUT TIME ZONE NOT NULL,
PRIMARY KEY (id),
UNIQUE (username)
)
so SQLAlchemy does not try to insert the "id" column
INSERT INTO users (username, registration_date) VALUES (%(username)s, %(registration_date)s) RETURNING users.id
[generated in 0.00079s] {'username': 'gord', 'registration_date': datetime.datetime(2021, 5, 4, 10, 53, 9, 930021)}
which is apparently not valid for the table that you created yourself.

I get 'sqlalchemy.exc.OperationalError' in my Flask App

I am building a blogging website using Flask, I have added a functionality where you can follow a user and view their posts just like Instagram/Twitter. I have created 2 tables in my models.py file namely User, Post and followers I am learning to build this site referring to Corey Schafer's YouTube video series on Flask and Miguel Grinberg's Flask Website Tutorial, I have used flask sqlalchemy database
Here is the models.py file
followers = db.Table('followers',
db.Column('follower_id', db.Integer, db.ForeignKey('user.id')),
db.Column('followed_id', db.Integer, db.ForeignKey('user.id'))
)
class User(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
followed = db.relationship(
'User', secondary=followers,
primaryjoin=(followers.c.follower_id == id),
secondaryjoin=(followers.c.followed_id == id),
backref=db.backref('followers', lazy='dynamic'), lazy='dynamic')
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.image_file}')"
def follow(self, user):
if not self.is_following(user):
self.followed.append(user)
def unfollow(self, user):
if self.is_following(user):
self.followed.remove(user)
def is_following(self, user):
return self.followed.filter(
followers.c.followed_id == user.id).count() > 0
def followed_posts(self):
return Post.query.join(
followers, (followers.c.followed_id == Post.user_id)).filter(
followers.c.follower_id == self.id).order_by(
Post.timestamp.desc())
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), unique=True, nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"User('{self.title}', '{self.date_posted}')"
here are the routes I have written to follow and unfollow a user in my routes.py file
#app.route('/follow/<username>')
#login_required
def follow(username):
user = User.query.filter_by(username=username).first()
if user is None:
flash('User {} not found.'.format(username))
return redirect(url_for('home'))
if user == current_user:
flash('You cannot follow yourself!')
return redirect(url_for('user', username=username))
current_user.follow(user)
db.session.commit()
flash('You are following {}!'.format(username))
return redirect(url_for('user', username=username))
#app.route('/unfollow/<username>')
#login_required
def unfollow(username):
user = User.query.filter_by(username=username).first()
if user is None:
flash('User {} not found.'.format(username))
return redirect(url_for('home'))
if user == current_user:
flash('You cannot unfollow yourself!')
return redirect(url_for('user', username=username))
current_user.unfollow(user)
db.session.commit()
flash('You are not following {}.'.format(username))
return redirect(url_for('user', username=username))
when I type 'url/user/' the page that leads me the user's profile page it throws an error like this
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: followers [SQL: 'SELECT count(*) AS count_1 \nFROM (SELECT user.id AS user_id, user.username AS user_username, user.email AS user_email, user.image_file AS user_image_file, user.password AS user_password \nFROM user, followers \nWHERE followers.followed_id = ? AND followers.follower_id = user.id) AS anon_1'] [parameters: (1,)]
How do I get this working?
Its over two years since this question was posted, but because it hasn't been answered, let me answer it.
The problem is occurring because no user has been created yet. A look at your unfollow(username) and unfollow(username)view functions means that you are supposed to have a user with a username already in the system. The two view functions are retrieving the specific user using user = User.query.filter_by(username=username).first(). This means your view function for the user is created using a username, which should be unique for each user, ie.
#app.route('/user/<username>')
#login_required
def user(username):
user = User.query.filter_by(username=username).first()
#....
Once a user is registered and is logged in you can then type '127.0.0.1:5000/user/foo' assuring the username is foo and assuming you are using the default method to your application.

SQLALCHEMY - couldn't get new record after insert with stored procedure

I use SQLALCHEMY with ORM class as follow:
Registration Class / Table:
class Registration(db.Model):
""" Activation Registrations Model for storing user Registrations related details """
__tablename__ = "user_registrations"
RegistrationID = db.Column(db.Integer, nullable=False, unique=True, primary_key=True, autoincrement=True)
RegistrationType = db.Column(db.Enum('Local', 'Facebook', 'Google'), nullable=False, server_default=text('Local'))
UserID = db.Column(db.Integer, db.ForeignKey('users.UserID'), nullable=False)
Email = db.Column(db.String(255), nullable=False)
#orm.reconstructor
def init_on_load(self):
# private
self.__dao = DAO(db)
def __init__(self, registration_type, user_id, email):
# private
self.__dao = DAO(db)
# public
self.RegistrationType = registration_type
self.UserID = user_id
self.Email = email
def save(self):
stored_proc = 'pUserRegister'
parameter = [self.UserID, str(self.RegistrationType), str(self.Email)]
result = self.__dao.call_procedure(stored_proc, parameter)
return {'status': status, 'message': message, 'data': data}
User class/Table:
class User(db.Model):
""" User Model for storing user related details """
__tablename__ = "users"
UserID = db.Column(db.Integer, primary_key=True, autoincrement=True)
Email = db.Column(db.String(255), unique=True, nullable=False)
UserName = db.Column(db.String(255), unique=True, nullable=False)
# relationships
Registrations = db.relationship('Registration', backref='users', lazy='dynamic')
def __init__(self, email, username):
# private
self.__dao = DAO(db)
# public
self.Email = email
self.UserName = username
#orm.reconstructor
def init_on_load(self):
# private
self.__dao = DAO(db)
#staticmethod
def register(registration_type, user_id, email):
if user_id and user_id > 0:
# check if user exists
user = User.query.filter(User.UserID == user_id).first()
if not user:
return {'status': False, 'data': {'message': 'Invalid User'}}
# initiate Registration
reg = Registration(registration_type, user_id, email)
result = reg.save()
return result
with DAO Class:
class DAO(object):
def __init__(self, db):
# Unpack Other Database Arguments Here
self.__db = db
engine = self.__db.engine
self.connection = engine.raw_connection()
def call_procedure(self, procedure, data=()):
try:
with self.connection.cursor(MySQLdb.cursors.DictCursor) as cursor:
cursor.callproc(procedure, data)
result = json.dumps(cursor.fetchall(), cls=DateTimeEncoder)
result = json.loads(result)
result = {"status": True, "data": result}
return result
except (MySQLdb.Error, MySQLdb.Warning) as e:
log.info('>>>>> Exception: %s <<<<<', e)
result = {'status': False, 'data': {'message': "ERROR: {}".format(e)}}
finally:
cursor.close()
self.connection.commit()
self.connection.close()
return result
so i tried to execute my code as follow: (just for testing to get userID 70)
user = User.query.filter(User.UserID == 70).first()
log.info('>>>>> debug1: %s <<<<<', user)
with code above, I can get the user object propoerly
then I do below:
resp = User.register(registration_type='Facebook', user_id=None, email='asd#aaswrtr.com')
log.info('>>>>> debug2: %s <<<<<', resp['data']['UserID'])
with code above I can see that the stored proc is executed properly and I can get the newly inserted ID from resp['data']['UserID'] and I can see data recorded in MYSQL DB
then I execute below to get the data that I just inserted using SP above:
user = User.query.filter(User.UserID == resp['data']['UserID']).first()
log.info('>>>>> debug3: %s <<<<<', user)
Problem: I received user = None in my last statement above.
what's possibly went wrong here?

Flask SqlAlchemy many to many relationship only returns one result when accessing by relationship name

I have a simple many to many relationship using sql Alchemy like this:
file_favorites = db.Table('file_favorites',
db.Column('file_id', db.Integer(), db.ForeignKey('file.id')),
db.Column('user_id', db.Integer(), db.ForeignKey('user.id')),
db.Column('created_at', db.DateTime(), default=db.func.now()))
class File(db.Model, helpers.ModelMixin):
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
name = db.Column(db.Unicode, nullable=False)
description = db.Column(db.Unicode, nullable=False)
created_at = db.Column(db.DateTime(), default=func.now())
last_updated = db.Column(db.DateTime(), default=func.now(), onupdate=func.now())
user_id = db.Column('user_id', db.Integer(), db.ForeignKey('user.id'), nullable=False, index=True)
user = db.relationship('User')
favorited_by = db.relationship('User', secondary=file_favorites, lazy='dynamic')
def is_favorite_of(self, user):
query = File.query
query = query.join(file_favorites)
query = query.filter(file_favorites.c.file_id == self.id)
query = query.filter(file_favorites.c.user_id == user.id)
return query.count() > 0
def favorite(self, user):
if not self.is_favorite_of(user):
self.favorited_by.append(user)
def unfavorite(self, user):
if self.is_favorite_of(user):
self.favorited_by.remove(user)
I would expect that accessing the favorited_by property would result in a query that tries to return a list of users that have favorited this file. However, it seems that the query is only accessing the FIRST user to have favorited this file. I'm puzzled by this, and expect that I don't correctly understand sqlalchemy relationships. Here is the result i'm experiencing:
def create_model(model_class, *args, **kwargs):
model = model_class(*args, **kwargs)
db.session.add(model)
db.session.commit()
return model
def test_favorited_by(self):
user = create_model(User, username='user', email='user#user.net', password='password')
user1 = create_model(User, username='user1', email='user1#user.net', password='password')
user2 = create_model(User, username='user2', email='user2#user.net', password='password')
file = create_model(File, name='file', description='a description', user=user)
file.favorite(user1)
file.favorite(user)
file.favorite(user2)
db.session.commit()
print file.favorited_by
results in this query:
SELECT "user".id AS user_id, "user".email AS user_email, "user".username AS user_username, "user".password AS user_password, "user".active AS user_active, "user".last_login_at AS user_last_login_at, "user".current_login_at AS user_current_login_at, "user".last_login_ip AS user_last_login_ip, "user".current_login_ip AS user_current_login_ip, "user".login_count AS user_login_count, "user".last_updated AS user_last_updated, "user".created_at AS user_created_at
FROM "user", file_favorites
WHERE :param_1 = file_favorites.file_id AND "user".id = file_favorites.user_id
Which ultimately returns user1, if the order is switched, the first user to favorite the file will always be the user returned.
Your problem is with is_favorite_of. It doesn't incorporate user into the check. You need to add another filter.
def is_favorite_of(self, user):
query = File.query
query = query.join(file_favorites)
query = query.filter(file_favorites.c.file_id == self.id)
query = query.filter(file_favorites.c.user_id == user.id)
return query.count() > 0
Alternatively, this whole function can be simplified to:
def is_favorite_of(self, user):
return user in self.favorited_by

Categories

Resources