Unable to assing IDs automatically in SQLite - sqlite

I have the following database model:
class Survey(db.Model):
id = db.Column(db.Integer, primary_key=True)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
question_ts = db.relationship('Questions')
class Questions(db.Model):
id = db.Column(db.Integer, primary_key=True)
survey_id = db.Column(db.Integer, db.ForeignKey('survey.id'), nullable=False)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
lan_code = db.Column(db.String(3), nullable=False)
q1 = db.Column(db.String(100), nullable=False)
q2 = db.Column(db.String(100), nullable=False)
q3 = db.Column(db.String(100), nullable=False)
When I insert q1, q2, q3, it fails with a NOT Null constraint failed
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed: questions.survey_id
[SQL: INSERT INTO questions (survey_id, date_posted, lan_code, q1, q2, q3) VALUES (?, ?, ?, ?, ?, ?)]
[parameters: (None, '2021-10-06 19:36:08.192194', 'en', 'how are you?', 'Did you get vaccinated?', 'When is your birthday?')]
It works perfectly if I assign IDs manually for the survey. However, is there a way to make the database handle this?

If you are creating a new Survey, you would do it like this:
qs = Questions(q1='Why?', q2='What?', q3='When?')
survey = Survey(question_ts=[qs])
db.session.add(survey)
db.session.commit()
SQLAlchemy will recognise that the objects are related and set up the keys and relationship.
If you are adding a Questions to an existing Survey you append to the relationship:
survey = session.query(Survey).first()
qs = Questions(q1='Why?', q2='What?', q3='When?')
survey.question_ts.append(qs)
db.session.commit()
If you need to obtain ids before committing, add the object(s) to the session and then call the session's flush method.

Related

"TypeError: NoneType is not subscriptable" when executing multiple queries

Member function that retrieves db.
def GetDb(self):
db = getattr(g, '_database', None)
if db is None:
db = g._database = sqlite3.connect(self.path)
db.row_factory = sqlite3.Row
return db
Member function that returns list from db queries
def GetOrderItemsList(self, orderid):
list = []
with app.app_context():
db = self.GetDb()
cur = db.execute('SELECT * FROM ordersList WHERE orderId = ?',[orderid])
records = cur.fetchall();
for row in records:
print(row)
invid = row['inventoryId']
OrderItem
OrderItem.orderId = row['orderId']
OrderItem.productId = row['inventoryId']
OrderItem.productName = 'none'
OrderItem.quantity = row['quantity']
OrderItem.productPrice = row['price']
nextcur = db.execute('SELECT * FROM inventory WHERE invId = ?', [invid])
#nextcur = db.execute('SELECT * FROM inventory WHERE invId = 1') #works
res = nextcur.fetchone();
OrderItem.productName = res['invName']
print(res['invName'])
list.append(OrderItem)
return list
OrderItem:
class OrderItem(object):
def __init__(self, ordId, invId, name, quantity, price):
self.orderId = ordId
self.productId = invId
self.productName = name
self.quantity = quantity
self.productPrice = price
Error message:
Traceback error
OrderItem.productName = res['invName']
TypeError: 'NoneType' object is not subscriptable
Error
nextcur = db.execute('SELECT * FROM inventory WHERE invId = ?', [invid])
Works
nextcur = db.execute('SELECT * FROM inventory WHERE invId = 1')
Been fighting this for many hours. Searching on google. Reading questions on here.
Any help would be appreciated.
The error
'NoneType' object is not subscriptable
Means that you're trying to access an object's key of an object that doesn't exist, i.e. the object is None.
Please check that here
[invid]
invid is not None, i.e. print (invid)
Also, the issue could be that here
res['invName']
res is None, please check the contents of res (with print, etc) before accessing invName, as it is None.
Fix with join, item instances and img for order product list.
Inventory and OrderItems
create table inventory(invId integer PRIMARY KEY AUTOINCREMENT NOT NULL, invName varchar(50), description varchar(100), invImg varchar(50) ,category integer ,quantity integer, price real);
create table ordersList(orderId integer, inventoryId integer, orderQuantity integer, orderPrice real);
class OrderItem(object):
def __init__(self, ordId, invId, img, name, quantity, price):
self.orderId = ordId
self.productId = invId
self.productName = name
self.productImg = img
self.quantity = quantity
self.productPrice = price
def GetOrderItemsList(orderid):
list = []
db = get_db()
cur = db.execute('SELECT orderId, inventoryId, orderQuantity, orderPrice,
inventory.invName AS invName, inventory.invImg AS invImg FROM ordersList INNERJOIN
inventory ON inventory.invId= ordersList.inventoryId WHERE orderId = ?', [orderid])
records = cur.fetchall();
for row in records:
item = OrderItem(row['orderId'], row['inventoryId'],
row['invImg'], row['invName'],
row['orderQuantity'], row['orderPrice'] )
list.append(item)
return list

Why is user_id column NULL? sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed: comment.user_id

Using Flask-SQLalchemy I am trying to submit a WTF-form to a table within a SQLite database. However, I am receiving the following error:
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed: comment.user_id
I understand this to mean that the Flask app is currently trying to put a NULL into a non-nullable column. Though I don't understand why this might be happening because the logic is copied from another form, post, which is working perfectly fine, i.e. User.id is being inserted into Post.user_id.
What I aiming to achieve is to insert user.id into comments.user_id.
How can I achieve this? What is causing the current issue?
Code:
models.py
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)
#new
batches = db.relationship('Batch', backref='author', lazy=True)
comments = db.relationship('Comment', backref='author', lazy=True)
def get_reset_token(self, expires_sec=1800):
s = Serializer(current_app.config['SECRET_KEY'], expires_sec)
return s.dumps({'user_id': self.id}).decode('utf-8')
#staticmethod
def verify_reset_token(token):
s = Serializer(current_app.config['SECRET_KEY'])
try:
user_id = s.loads(token)['user_id']
except:
return None
return User.query.get(user_id)
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.image_file}')"
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), 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)
# THIS HERE IS THE CLASS THAT I AM EXPERIENCING THIS ERROR WITH
class Comment(db.Model):
id = db.Column(db.Integer, primary_key=True)
comment = db.Column(db.Text, nullable=False)
tag_1 = db.Column(db.String(50), nullable=True)
tag_2 = db.Column(db.String(50), nullable=True)
tag_3 = db.Column(db.String(50), nullable=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
routes.py
#tools.route("/toolkit/comments/new", methods=['GET', 'POST'])
#login_required
def add_comment():
form = comment_form()
if form.validate_on_submit():
comment = Comment(comment=form.comment.data, tag_1=form.tag_1.data, tag_2=form.tag_2.data, tag_3=form.tag_3.data)
db.session.add(comment)
db.session.commit()
flash('Your comment has been added!', 'success')
return redirect(url_for('tools.comments', username=user))
return render_template('add_comments.html', form=form)
Thanks in advance.
This line:
comment = Comment(comment=form.comment.data, tag_1=form.tag_1.data, tag_2=form.tag_2.data, tag_3=form.tag_3.data)
is missing the parameter user_id right ? Just provide that parameter with the desired value.

FLASK-ADDING DATETIME CALCULATION INTO DATABASE

I m trying to perform a little calculation and Logic on date.time with Flask application.
1.) the application will calculate the difference between issue date and expiry date called "remaining days" , The application will check if remaining days is less than 365 days and trigger a function
I attempted the first logic to manipulate the data and submit to database
`#bp.route('/cerpacs/add', methods=['GET', 'POST'])
#login_required
def add_cerpac():
"""
Add a an Cerpac/ expartriates to the database
"""
check_admin()
add_cerpac = True
form =CerpacForm()
if form.validate_on_submit():
cerpac = Cerpac(cerpac_serial_no=form.cerpac_serial_no.data,
cerpac_issue_date= form.cerpac_issue_date.data,
cerpac_exp_date=form.cerpac_exp_date.data,
employee =form.employee.data, )
form.cerpac_issue_date.data = cerpac.cerpac_issue_date
form.cerpac_exp_date.data = cerpac.cerpac_exp_date
if request.method == 'POST':
todays_date = datetime.now()
t = cerpac.cerpac_issue_date
t1 = cerpac.cerpac_exp_date
remaining_days = t1 - t
print(remaining_days) - good prints my result!
remaining_days = cerpac.remaining_days ----not adding to database
try:
add cerpac to the database
db.session.add(cerpac)
db.session.commit()
flash('You have successfully added a Cerpac.' )`
`
my model:
class Cerpac(db.Model):
__tablename__ = 'cerpacs'
id = db.Column(db.Integer, primary_key=True)
cerpac_issue_date = db.Column(db.DateTime)
cerpac_exp_date=db.Column(db.DateTime)
remaining_days = db.Column(db.DateTime)
cerpac_serial_no = db.Column(db.String(60))
cerpac_upload = db.Column(db.String(20), default='cerpac.jpg')
renew_status = db.Column(db.Boolean, default=False)
process_status = db.Column(db.Boolean, default=False)
renewcerpac_id = db.Column(db.Integer, db.ForeignKey('renewcerpacs.id'))
employee_id = db.Column(db.Integer, db.ForeignKey('employees.id'))
def __repr__(self):
return '<Cerpac {}>'.format(self.name) model:
I want to add this to database and eventually write a function like this:
I had a mistake also in the code because I had error issue_date not defined. How do I define issue_date as a date.time variable?
def remaining_days(issue_date, expired_date):
issue_date = datetime(issue_date)
days_to_go = expired - issue
if days_to_go == 365:
renew_status== True
print("time to renew")
print("We are Ok")
I would simplify this to something like:
from datetime import datetime
class Cerpac(db.Model):
...
cerpac_exp_date=db.Column(db.DateTime)
...
#property
def remaining_days(self):
return (self.cerpac_exp_date - self.cerpac_issue_date).days
#property
def days_to_expiry(self):
return (self.cerpac_exp_date - datetime.now()).days
Then, days_to_expiry and remaining_days become properties calculated when you query, and update automatically when they renew their cards.

Flask, SQLAlchemy: How to make column autoincrement

I'm defining a model like this:
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
first = db.Column(db.String(64))
last = db.Column(db.String(64))
dob = db.Column(db.Date)
street_addr1 = db.Column(db.String(64))
street_addr2 = db.Column(db.String(64))
city = db.Column(db.String(64))
state = db.Column(db.String(2))
zip = db.Column(db.String(9))
gender = db.Column(db.Enum('M', 'F'))
home_box = db.Column(db.String(32))
username = db.Column(db.String(64), unique=True, index=True)
password_hash = db.Column(db.String(128))
#property
def password(self):
raise AttributeError('password is not a readable attribute')
#password.setter
def password(self, password):
self.password_hash = generate_password_hash(password)
def verify_password(self, password):
return check_password_hash(self.password_hash, password)
def __repr__(self):
return '<User %r>' % self.username
#login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
views.py:
#main.route('/', methods=['GET', 'POST'])
def index():
form = RegistrationForm()
if form.validate_on_submit():
user = User()
user.username = form.username.data
user.first = form.first_name.data
user.last = form.last_name.data
user.city = form.city.data
user.dob = form.dob.data
user.gender = form.gender.data
user.home_box = form.home_box.data
user.state = form.state.data
user.street_addr1 = form.street_addr1.data
user.street_addr2 = form.street_addr2.data
user.zip = form.zip.data
user.password = form.password.data
db.session.add(user)
db.session.commit
Right now, inserts are failing because the id is not set:
sqlalchemy.exc.IntegrityError: (IntegrityError) constraint failed 'INSERT INTO users (first, last, dob, street_addr1, street_addr2, city, state, zip, gender, home_box, username, password_hash) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)' ('Nate', 'Reed', '1980-11-11', '', '', '', '', '', 'male', '', 'natereed', 'pbkdf2:sha1:1000$N8JHXEDU$24a7724ae9edda81a73e6b92d23aa576ad8284aa')
How do I make id autoincrement? My understanding is it has to be done at the table (not column) level. How do I do this in the code above?
I figured out the problem was I was trying to insert a value for gender that is not valid. It's an enum with values 'M' or 'F'.
It would be nice if the form could just be generated from the model, as that would eliminate the potential for this error. Any pointers on doing that with Flask?

Reading multiple rows of data using sqldatareader

I've the below sql statement as follows:
SELECT * FROM ViewSectorInvestments WHERE AccountNumber = #AccountNumber
Fields in ViewSectorInvestments:
AccountNumber
SectorName
AmountInvested
I'm trying to compute the AmountInvested in each sector against the total investments.
So the formula will be: AmountInvested/TotalInvestments * 100
my code is as follows:
string DMConnectionString = ConfigurationManager.ConnectionStrings["DMConnectionString"].ConnectionString;
SqlConnection DMConnection = new SqlConnection(DMConnectionString);
DMConnection.ConnectionString = DMConnectionString;
string DMCommandText = "SELECT Name,RiskProfile,AccountNumber,TotalInvestments FROM ViewClientDetails WHERE AccountNumber = #AccountNumber; SELECT * FROM ViewSectorInvestments WHERE AccountNumber = #AccountNumber ;SELECT * FROM ViewStockTypeInvestments WHERE AccountNumber = #AccountNumber ";
SqlCommand DMCommand = new SqlCommand(DMCommandText, DMConnection);
DMCommand.Parameters.AddWithValue("#AccountNumber", lb_AcctNum.Text);
DMConnection.Open();
SqlDataReader DMReader = DMCommand.ExecuteReader();
ArrayList SectorArray = new ArrayList();
ArrayList StockTypeArray = new ArrayList();
while (DMReader.Read())
{
CustName.Text = DMReader["Name"].ToString();
lb_Risk.Text = DMReader["RiskProfile"].ToString();
T_Investment.Text = DMReader.GetDecimal(DMReader.GetOrdinal("TotalInvestments")).ToString("N2");
Client_RiskProfile.Text = DMReader["RiskProfile"].ToString();
//encounter error when i add the datas into arraylist.
//System.IndexOutOfRangeException: SectorName
SectorArray.Add(DMReader.GetOrdinal("SectorName").ToString());
StockTypeArray.Add(DMReader.GetOrdinal("BlueChipName").ToString());
foreach( Object objReader in SectorArray){
//compute the percentage of amount invested in each sector
//check if the percentage is more than 25%
//if it is more than 25% lbMsg (an label) shows the name of the sector.
}
}
DMReader.Close();
DMConnection.Close();
}
When i test out the sql statement :
SELECT * FROM ViewSectorInvestments WHERE AccountNumber = #AccountNumber
The result i got is :
AccountNumber SectorName AmountInvested
1001 Commerce 97230.00000
1001 Construction 389350.00000
1001 Finance 222830.00000
1001 Hotel 14910.00000
1001 Loans 105070.00000
1001 Manufacturing 1232210.00000
1001 Mining/Quarrying 32700.00000
I encountered System.IndexOutOfRangeException: SectorName.
What's wrong with my code?
Please advice me. Thanks in advance.
string DMCommandText = "SELECT Name,RiskProfile,AccountNumber,TotalInvestments FROM ViewClientDetails WHERE AccountNumber = #AccountNumber; SELECT * FROM ViewSectorInvestments WHERE AccountNumber = #AccountNumber ;SELECT * FROM ViewStockTypeInvestments WHERE AccountNumber = #AccountNumber ";
This CommandText contains multiple queries. Only the results from the last SELECT statement will be returned to the SqlDataReader.
SectorArray.Add(DMReader.GetOrdinal("SectorName").ToString());
You are trying to access the column ordinal of a field called "SectorName" in your SqlDataReader. The problem causing your exception is probably that the column doesn't exist, but it's hard to say since you are using SELECT * in your CommandText.

Resources