Search code examples
pythonpython-3.xsqlitetkinterdb-browser-sqlite

Need help for Python and SQLite --> TypeError: 'NoneType' object is not subscriptable


I need your help in order to solve this problem.

I am trying to enter a line in a database where the program has to find a material X in the database and then get the quantity value. After that, the program creates a new line where it adds the stock entered by the user + the current stock in a new line. The program works as long as the last line in the database is the same material X, but in case the last line is for material Y, then it raises this error.

Here I attach the code:

from tkinter import *
from tkinter import ttk
from datetime import datetime
import sqlite3

class Main:

    db_name = 'materiales.db'
    
    def __init__(self,window):
        self.wind = window
        self.wind.title('Stock App')

        #create frame
        frame = LabelFrame(self.wind, text = 'Add stock')
        frame.grid(row = 0, column = 0, columnspan = 3, pady = 20)

        # Name Input
        Label(frame, text = 'Name: ').grid(row = 1, column = 0)
        self.name = Entry(frame)
        self.name.focus()
        self.name.grid(row = 1, column = 1)

        # Quantity Input
        Label(frame, text = 'Quantity: ').grid(row = 2, column = 0)
        self.quantity = Entry(frame)
        self.quantity.grid(row = 2, column = 1)

        # Button Add Stock
        ttk.Button(frame, text = 'Add Stock', command = self.add_stock).grid(row = 3, columnspan = 2, sticky = W + E)

        #Log Message
        self.message = Label(text = '', fg = 'red')
        self.message.grid(row = 3, column = 0, columnspan = 2, sticky = W + E)

        #Button Search Stocks
        ttk.Button(text = 'Search Stocks', command = self.search_stocks).grid(row = 5, column = 0, columnspan = 3, pady = 20, sticky = W + E) 



    def run_query(self, query, parameters = ()):
        with sqlite3.connect(self.db_name) as conn:
            cursor = conn.cursor()
            result = cursor.execute(query, parameters)
            conn.commit()
        return result

    def validation(self):
        return len(self.name.get()) != 0 and len(self.quantity.get()) !=0
        

    def add_stock(self):
        time = datetime.now().strftime("%B %d, %Y")
        hour = datetime.now().strftime("%I:%M%p")
        query = 'SELECT totalstock FROM stocks WHERE name = ? AND MovementID = ( SELECT max( MovementID ) FROM stocks)'
        parameters = (self.name.get(),)
        lastrecord = self.run_query(query, parameters)
        total = lastrecord.fetchone()[0]
        total += int(self.quantity.get())
        if self.validation():
            query = 'INSERT INTO stocks VALUES(NULL, ?, ?, ?, ?, ?)'
            parameters = (self.name.get(), self.quantity.get(), total, time, hour)
            self.run_query(query, parameters)
            self.message['text'] = 'Stock for {} added succesfully'.format(self.name.get())
            self.name.delete(0, END)
            self.quantity.delete(0, END)
        else:
            self.message['text'] = 'Name and Quantity required'
        self.get_product()

    def search_stocks(self):
        self.edit_wind = Toplevel()
        self.edit_wind.title = 'Search Stocks'

        #Name Product
        Label(self.edit_wind, text = 'Name: ').grid(row = 0, column = 1)
        name = Entry(self.edit_wind)
        name.grid(row = 0, column = 2)

        Button(self.edit_wind, text = 'Search', command = lambda: self.edit_records(new_name.get(), name, new_price.get(), old_price)).grid(row = 4, column = 2, sticky = W)

    def edit_records(self, name):
        query = 'SELECT totalstock FROM stocks WHERE name = ? AND MovementID = ( SELECT max( MovementID ) FROM stocks)'
        parameters = (name)
        self.run_query(query, parameters)
        self.edit_wind.destroy()
        self.message['text'] = 'Total stock is {}'.format(totalstock)
        self.get_product()

        
if __name__ == '__main__':
    window = Tk()
    application = Main(window)
    window.mainloop()

Here I attach the complete error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Users\Xavi\AppData\Local\Programs\Python\Python39\lib\tkinter\__init__.py", line 1884, in __call__
    return self.func(*args)
  File "C:\Users\Xavi\Desktop\Program\stock\stocklist.py", line 58, in add_stock
    total = lastrecord.fetchone()[0]
TypeError: 'NoneType' object is not subscriptable
>>> 

Happy new year 2021 and thanks for your help


Solution

  • This line causes the error if no records match the selection criteria in the query:

    total = lastrecord.fetchone()[0]
    

    If no records match then lastrecord.fetchone() evaluates to None, resulting in the TypeError.

    You could handle this by using a try/except block:

    try:
        total = lastrecord.fetchone()[0]
    except TypeError:
        total = 0
    

    or an if/else:

    row = lastrecord.fetchone()
    if row is None:
        total = 0
    else:
        total = row[0]
    

    or more succintly

    row = lastrecord.fetchone()
    total = row[0] if row is not None else 0