I have the following code:
uic.loadUi("mainwindow.ui", self)
self.db = QSqlDatabase.addDatabase('QSQLITE')
self.db.setDatabaseName('people.db')
self.db.open()
try:
if self.db.isOpen():
print('DB open')
# self.pushButtonClear.clicked.connect(self.clearFields)
# self.pushButtonSave.clicked.connect(self.insertRowToModel)
self.pushButtonDelete.clicked.connect(self.deleteTableRow)
self.model = QSqlRelationalTableModel(db=self.db)
self.model.setTable("person")
self.model.setEditStrategy(QSqlTableModel.OnFieldChange)
self.group_index = self.model.fieldIndex("GroupId") #foreign key
self.model.setRelation(self.group_index, QSqlRelation("Groups", "GroupId", "GroupName"))
self.model.select()
self.relModel = self.model.relationModel(self.group_index)
self.comboBoxGroup.setModel(self.relModel)
self.comboBoxGroup.setModelColumn(self.relModel.fieldIndex("GroupName"))
self.tableView.setModel(self.model)
self.mapper = QDataWidgetMapper()
self.mapper.setModel(self.model)
self.mapper.setItemDelegate(QSqlRelationalDelegate(self))
self.mapper.addMapping(self.lineEditId, 0)
self.mapper.addMapping(self.lineEditForename, 1)
self.mapper.addMapping(self.lineEditSurename, 2)
self.mapper.addMapping(self.dateEditBirthday, 3)
self.mapper.addMapping(self.lineEditCity, 4)
self.mapper.addMapping(self.comboBoxGroup, self.group_index)
self.mapper.toFirst()
except:
self.db.close()
print('Exception raised')
in line: self.comboBoxGroup.setModelColumn(self.relModel.fieldIndex("GroupName"))
it gives an AttributeError: 'NoneType' object has no attribute 'fieldIndex'
because the self.relModel = self.model.relationModel(self.group_index) results in a None type. It could not be setup. When i enter the column index as a number like this: self.comboBoxGroup.setModelColumn(self.relModel.fieldIndex(1)) the data shows up at least, but the combobox is not filled. What is going wrong here?
I have found the problem:
self.group_index = self.model.fieldIndex("group") #foreign key
field name was incorrect. Now it works but only gives entries where there is
an entry in the group table (inner join)
Related
I am trying to work around autocomplete dropdown combobox which works fine with database. but when i try to fetch data after updating database in runtime I got AttributeError: 'FarmerClass' object has no attribute 'farmer_name'. I tried other available solutions but still error is not solved. as of now, typo and syntax looks fine from the reference code which i was following.
the class which throws error
class FarmerClass(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.veg = []
self.farmer = []
self.buyers = []
self.fetch_data()
self.farmer_name = ttk.Combobox(self)
self.farmer_name['values'] = self.farmer
self.farmer_name.focus()
self.farmer_name.bind('<KeyRelease>', self.check_name)
self.farmer_name.bind('<<ComboboxSelected>>', self.get_data)
self.farmer_name.place(relx=0.028, rely=0.243, width=240, height=24)
self.product = ttk.Combobox(self )
self.product['values'] = self.veg
self.product.bind('<KeyRelease>', self.check_veg)
self.product.place(relx=0.028, rely=0.380,width=240, height=24)
self.buyer = ttk.Combobox(self )
self.buyer['values'] = self.buyers
self.buyer.bind('<KeyRelease>', self.check_buyer)
self.buyer.place(relx=0.028, rely=0.5237,width=240, height=24)
#======================= Entry btn ====================
self.entry_btn = tk.Button(self,Btn_base, text='Entry', command=self.entry_to_bill)
self.entry_btn.place(relx=0.481, rely=0.525,width=134, height=24)
def fetch_data(self, event=None):
cur.execute('SELECT * FROM vegetable ')
for i in cur.fetchall():
self.veg.append(i[0])
cur.execute('SELECT rowid, * FROM farmers ')
for i in cur.fetchall():
self.farmer.append(i[2])
cur.execute('SELECT rowid,name FROM buyers_avail ')
for i in cur.fetchall():
self.buyers.append(i[1])
self.farmer_name.configure(values= self.farmer) # getting error here
self.product.configure(values= self.veg)
self.buyer.configure(values= self.buyers)
def entry_to_bill(self, event=None):
name = self.buyer.get().lower()
cur.execute('SELECT name FROM buyers_avail WHERE name = ? ', [name])
bnames = cur.fetchall()
if bnames:
print(f'buyer {bnames} found')
else:
cur.execute('INSERT INTO buyers_avail (name) VALUES (?)',[name,])
db.commit()
self.buyer.delete(0, tk.END)
self.buyer.focus()
self.fetch_data()
if i try without those lines, farmer_name looks fine, product gets values of buyers and buyer dropdown goes empty.
please ask if anything required related to question.
The fetch_data function accesses farmer_name but you call it before defining farmer_name, which therefore doesn't exist at that point. You need to call fetch_data after defining farmer_name.
you're help is needed:
the mystery is located in Method setupNumRibs.
In my test setup the table contains only one row.
res = self.setData(self.index(0, 1), numRows )
Executes and does the table update as expected.
res = self.setData(self.index(1, 1), numRows )
Must fail, as the row to be updated does not exist.
res is FALS as expected, BUT on the cmd line I get:
model ErrT : 0
model Err text : ||
db ErrT : 0
db Err text : ||
Somwhow the
modelError = self.lastError()
Fails, I don't get the correct info back, but I don't see WHY :-(
The full code:
from Singleton.Singleton import Singleton
class ProcessorModel(QSqlTableModel, metaclass=Singleton):
def __init__(self, parent=None):
self.fileNamePath = ''
self.fileVersion = ''
# open database
self.db = QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName("processorModel.sqlite")
if not self.db.open():
logging.error(self.__className+ '.__init__ cannot open db')
super().__init__()
# make sure tables are there
self.rib_M = self.RibModel()
self.wing_M = self.WingModel()
def isValid( self, fileName ):
def setFileName( self, fileName ):
def openFile(self):
def readFile(self):
def remTabSpace(self, line):
def remTabSpaceQuot(self, line):
class WingModel(QSqlTableModel, metaclass=Singleton):
def createWingTable(self):
def __init__(self, parent=None):
def syncData(self, q):
class RibModel(QSqlTableModel, metaclass=Singleton):
__className = 'RibModel'
RibNumCol = 1
xribCol = 2
yLECol = 3
yTECol = 4
xpCol = 5
zCol = 6
betaCol = 7
RPCol = 8
WashinCol = 9
def createRibTable(self):
logging.debug(self.__className+'.createRibTable')
query = QSqlQuery()
query.exec("DROP TABLE if exists Rib;")
query.exec("create table if not exists Rib ("
"ID INT PRIMARY KEY,"
"RibNum varchar(50),"
"xrib varchar(50),"
"yLE varchar(50),"
"yTE varchar(50),"
"xp varchar(50),"
"z varchar(50),"
"beta varchar(50),"
"RP varchar(50),"
"Washin varchar(50));")
query.exec("INSERT into Rib (ID) Values( '1' );")
def __init__(self, parent=None):
'''
:method: Constructor
'''
super().__init__()
self.createRibTable()
self.setTable("Rib")
self.select()
self.setEditStrategy(QSqlTableModel.OnFieldChange)
def setupNumRibs(self, halfNumRibs):
logging.debug(self.__className+'.setupNumRibs')
numRows = self.rowCount()
res = self.setData(self.index(1, 1), numRows )
if not res:
modelError = self.lastError()
print('model ErrT : %s' %modelError.type())
print('model Err text : |%s|' %modelError.text())
print()
procM = ProcessorModel()
dbError = procM.db.lastError()
print('db ErrT : %s' %dbError.type())
print('db Err text : |%s|' %dbError.text())
print()
The Singleton Class can be found already here
There is no mystery if you read the docs:
QSqlError QSqlQueryModel::lastError() const
Returns information about the last error that occurred on the
database.
It is clearly indicated that lastError() indicates an error that happens when interacting with the database, but in your case it does not interact since the model first verifies that the QModelIndex is valid, and since yours is not valid then it returns immediately false without doing any transaction with the database.
On the other hand, don't complicate your problem by adding Singleton or other elements that are just noise. It would be recommended that for each question you create an MRE focused only on the problem and thus save us time to help you instead of having to eliminate silly code.
This isn't my code; I got it from https://www.youtube.com/channel/UC4KX0hatvRrOVy_D0nPlusg. The author didn't have the source code so I just had to type it up from the video. His worked fine but I kept getting this error:
File "D:\ProgramDevelopment\Python\Project\Python_GUI_IDEL\PythonDatabaseYoutube.py", line 45, in run_query
query_result= cursor.execute(query,parameters)
sqlite3.OperationalError: near ",": syntax error"
Link in github: https://github.com/ahmed-aya/Python_database/blob/master/Python_Database
from tkinter import *
from tkinter import ttk
import sqlite3
class Product(object):
def __init__(self,wind):
self.wind=wind
self.wind.title('IT products')
frame = LabelFrame (self.wind,text= 'Add new record')
frame.grid (row=0,column=1)
Label(frame,text='Name:').grid(row=1,column=1)
self.name =Entry(frame)
self.name.grid(row=1,column=2)
Label(frame,text='Price:').grid(row=2,column=1)
self.price =Entry(frame)
self.price.grid(row=2,column=2)
ttk.Button(frame,text='Add record',command=self.adding).grid(row=3,column=2)
self.message=Label(text='',fg='red')
self.message.grid(row=3,column=0)
self.tree=ttk.Treeview(height=10,column=2)
self.tree.grid(row=4,column=0,columnspan=2)
self.tree.heading('#0',text='Name',anchor=W)
self.tree.heading(2,text='Price',anchor=W)
ttk.Button(text='Delete record',command=self.deleting).grid(row=5,column=0)
ttk.Button(text='Edit record',command=self.editing).grid(row=5,column=1)
self.viewing_records()
def run_query (self, query, parameters=()):
with sqlite3.connect('database.db') as conn:
cursor = conn.cursor()
query_result= cursor.execute(query,parameters)
conn.commit()
return query_result
def viewing_records(self):
records = self.tree.get_children()
for element in records:
self.tree.delete(element)
query ='SELECT * FROM product ORDER BY name DESC'
db_rows = self.run_query (query)
for row in db_rows:
self.tree.insert('',0,text=row[1], values = row[2])
def validation (self):
return len (self.name.get()) !=0 and len (self.price.get()) !=0
def adding (self):
if self.validation():
query ='INSERT INTO product VALUES (NULL,?,?)'
parameters =(self.name.get(),self.price.get())
self.run_query(query,parameters)
self.message ['text'] = 'Record {} added'.format (self.name.get())
self.name.delete(0,END)
self.price.delete(0,END)
else:
self.message['text']='name field or price is empty'
self.viewing_records()
def deleting (self):
self.message['text']=''
try:
self.tree.item (self.tree.selection())['text']
except IndexError as e:
self.message['text']='Please, select recoard'
return
self.message['text']=''
name=self.tree.item (self.tree.selection())['text']
query='DELETE FROM product WHERE name=?'
self.run_query(query,(name,))
self.message['text']='Record {} deleted.'.format(name)
self.viewing_records()
def editing(self):
self.message['text']=""
try:
self.tree.item (self.tree.selection())['values'][0]
except IndexError as e:
self.message['text']='Please select record'
return
name = self.tree.item (self.tree.selection())['text']
old_price = self.tree.item (self.tree.selection())['values'][0]
self.edit_wind= Toplevel()
self.edit_wind.title('Edit Window')
Label (self.edit_wind,text='Old name: ').grid(row=0,column=1)
Entry (self.edit_wind,textvariable=StringVar(self.edit_wind,value=name),state='readonly').grid(row=0,column=2)
Label (self.edit_wind,text='New name: ').grid(row=1,column=1)
new_name = Entry(self.edit_wind)
new_name.grid(row=1,column=2)
Label (self.edit_wind,text='Old price: ').grid(row=2,column=1)
Entry (self.edit_wind,textvariable = DoubleVar(self.edit_wind,value=old_price),state='readonly').grid(row=2,column=2)
Label (self.edit_wind,text='New price: ').grid(row=3,column=1)
new_price=Entry(self.edit_wind)
new_price.grid(row=3,column=2)
Button(self.edit_wind,text='save changes', command=lambda:self.edit_records(new_name.get(),name,new_price.get(),old_price)).grid(row=4,column=2,sticky=W)
self.edit_wind.mainloop()
def edit_records(self, new_name,name,new_price,old_price):
query = 'UPDATE product SET name=?,price,=? WHERE name=? AND price =?'
parameters = (new_name,new_price,name,old_price)
self.run_query (query,parameters)
self.edit_wind.destroy()
self.message['text']='Record {} changed.'.format(name)
self.viewing_records()
if __name__== '__main__':
wind=Tk()
application = Product(wind)
wind.mainloop()
As your error says, you have a typo.
query = 'UPDATE product SET name=?,price,=? WHERE name=? AND price =?'
^ extra comma here
I am new to Python scripting and now is trying to design a window interface to save daily expense into EXCEL file.
I have written a QTableWidget to type in the daily expense information but found the error message "AttributeError: 'Window' object has no attribute 'tableWidget'" while saving the data into EXCEL file.
Can anyone give me the hint to move forward?
Below is my code for your reference.
class Window(QtGui.QWidget):
def __init__(self): #Initial a Window frame
super(Window, self).__init__()
self.labels() #insert labels
self.buttons() #insert buttons
self.draglists()
self.table()
.
.
.
def table(self):
table = QtGui.QTableWidget(self)
table.setRowCount(20)
table.setColumnCount(4)
table.resize(450, 300)
table.move(640, 100)
horHeader = ['Date', 'Category', 'Item', 'Expense']
table.setHorizontalHeaderLabels(horHeader)
def savefile(self):
filename = unicode(QtGui.QFileDialog.getSaveFileName(self, 'Save File', '', ".xls(*.xls)"))
wbk = xlwt.Workbook()
sheet = wbk.add_sheet("sheet", cell_overwrite_ok=True)
self.add2(sheet)
wbk.save(filename)
def add2(self, sheet):
for currentColumn in range(self.tableWidget.columnCount()):
for currentRow in range(self.tableWidget.rowCount()):
try:
teext = str(self.tableWidget.item(currentRow, currentColumn)).text()
sheet.write(currentRow, currentColumn, teext)
except AttributeError:
pass
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ex = Window()
ex.setGeometry (50, 50, 1200, 600)
ex.show()
ex.setWindowTitle("Search Engine for Expense")
sys.exit(app.exec_())
You're referencing something you haven't defined yet. Your class Window inherits from QtGui.QWidget, which doesn't have an attribute called tableWidget, yet you reference an attribute called tableWidget here:
def add2(self, sheet):
for currentColumn in range(self.**tableWidget**.columnCount()):
for currentRow in range(self.**tableWidget**.rowCount()):
try:
teext = str(self.**tableWidget**.item(currentRow, currentColumn)).text()
sheet.write(currentRow, currentColumn, teext)
except AttributeError:
pass
Hence the error. If you want self.tableWidget to reference the table you made in table(self), you'd need to make it an instance attribute at the end of the function like so:
def table(self):
table = QtGui.QTableWidget(self)
table.setRowCount(20)
table.setColumnCount(4)
table.resize(450, 300)
table.move(640, 100)
horHeader = ['Date', 'Category', 'Item', 'Expense']
table.setHorizontalHeaderLabels(horHeader)
self.tableWidget = table
That will allow your other functions to access the table and its attributes, including .columnCount() and .rowCount().
Hope that helps.
I would like to transfer data between two QtTableView. To do that, I first select the row to transfer then click on "to_X_table".
But I don't understand how to fill the second tableview with the first one.
I tried :
self.to_X_table.clicked.connect(self.to_X_tableView)
def to_X_tableView(self):
self.proxy = QtCore.QSortFilterProxyModel()
self.proxy.setSourceModel(self.tableWidget_Input_Col.selectionModel())
self.tableView_X.setModel(self.proxy)
self.tableView_X.resizeColumnsToContents()
I get this message :
TypeError : setSourceModel(self,QAbstractItemModel) : 1 argument unexpected type QItemSelectionModel
I'dont really know what self.tableWidget_Input_Col.selectionModel() return. I guess it was a model. But seems not.
I also tried to create my own model like this (following this post Get data from every cell from a QTableView)
def to_X_tableView(self):
indexes = self.tableWidget_Input_Col.selectionModel().selectedRows()
self.model = QtGui.QStandardItemModel()
for index in sorted(indexes):
print('Row %d is selected' % index.row())
self.model.invisibleRootItem().appendRow(
QtGui.QStandardItem(self.tableWidget_Input_Col.model.index(index.row, 0)))
self.proxy = QtCore.QSortFilterProxyModel()
self.proxy.setSourceModel(self.tableWidget_Input_Col.selectionModel())
self.tableView_X.setModel(self.proxy)
self.tableView_X.resizeColumnsToContents()
but I get this error :
Traceback (most recent call last):
File "ChartGUI.py", line 151, in to_X_tableView
QtGui.QStandardItem(self.tableWidget_Input_Col.model.index(index.row, 0)
AttributeError: 'builtin_function_or_method' object has no attribute 'index'
Finaly, I solve my problem. I didn't consider the model the first time.
Here :
self.modelX = QtGui.QStandardItemModel()
indexes = self.tableWidget_Input_Col.selectionModel().selectedIndexes()
temp=self.tableWidget_Input_Col.selectionModel().model() # need to consider the model !
for index in sorted(indexes):
self.modelX.invisibleRootItem().appendRow(
QtGui.QStandardItem(str(temp.data(index))))
self.proxy = QtCore.QSortFilterProxyModel()
self.proxy.setSourceModel(self.modelX)
self.tableView_X.setModel(self.proxy)
self.tableView_X.resizeColumnsToContents()