How does sibling or siblingAtRow() function works to retrieve the value from hidden Column in QTableWidget? - pyqt

I have a database from which data is coming into a QTableWidget. The table in the database has the following Columns,
ID (Primary key, auto-increment value)
Name
Location
The QTableWidget has the following columns (that I have added)
ID (this column, I have hidden. and it contains the value of "ID" column from the Database Table)
Sr # (Represents the Row Number of the table)
Name (Contains "name" from the database table)
Location (Contains "Location from the database table)
Actions (Contains a Delete Button for that Row)
By hidden, I mean to say that I have made this column hidden using the folliwng command,
self.ui.table.setColumnHidden(0, True);
This is how I am populating my QTableWidget and creating a Delete Function,
def get_data(self):
mycursor = self.DB.cursor()
Subquery = "select id, name, location "
Subquery += " from tbl_person"
mycursor.execute(Subquery)
numcols = len(mycursor.fetchall()[0])
mycursor.execute(Subquery)
numrows = len(mycursor.fetchall())
self.ui.table.setRowCount(numrows)
self.ui.table.setColumnCount(numcols+2)
mycursor.execute(Subquery)
tablerow = 0
for row in mycursor.fetchall():
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
delete_button = QPushButton("Delete Data")
delete_button.clicked.connect(self.executeDeleteFunction)
# delete_button.setStyleSheet(delete_push_button) -> Only for styling
self.ui.table.setItem(tablerow, 0, PySide2.QtWidgets.QTableWidgetItem(str(row[0])))
self.ui.table.setItem(tablerow, 1, PySide2.QtWidgets.QTableWidgetItem(str(tablerow+1)))
self.ui.table.setItem(tablerow, 2, PySide2.QtWidgets.QTableWidgetItem(str(row[1])))
self.ui.table.setItem(tablerow, 3, PySide2.QtWidgets.QTableWidgetItem(str(row[2])))
self.ui.table.setCellWidget(tablerow, 4, delete_button)
tablerow += 1
self.ui.table.setColumnHidden(0, True)
#self.ui.registered_table.horizontalHeader().setSectionResizeMode(PySide2.QtWidgets.QHeaderView.Stretch)
self.ui.table.resizeColumnsToContents()
def executeDeleteFunction(self):
self.person_id = self.ui.table.selectionModel().selectedIndexes()[0]
self.person_id = self.person_id.row()
mycursor = self.DB.cursor()
sql = "delete from tbl_person where id = %s"
val = (id, )
mycursor.execute(sql, val)
print("Deletion Successful")
On the Deletion Function, what this code does is basically gets the value of the **Sr # ** Column from the QTableWidget and deletes the data according to that, i.e. it is getting me the value from the visible first column and not the actual first column. But, I want the data from the "ID" column of the QTableWidget which is hidden
I tried to look up on how to get the value from the first hidden column on the QTableWidget and ended up with this link: How to get data from hidden 'id' column in QtableWidget
This apparently solves my issue but I can not seem to make it work for my code. I don't want to retrieve values of multiple Rows but only of one row so how do I do this (as I am only deleting one row. But in the question mentioned, I believe that it is getting data from multiple rows due to that for each loop)?
Moreover, I tried to find help regarding the functionality of sibling function (which is provided in the answer of above question) however I could not find any good resource on this function (i.e. how to use this, or some practical example and etc.)
I tried the following with Sibling function to obtain the value of first hidden column of the Selected Row but it did not work,
self.value = self.table.selectedItems()[0]
self.value = sibling(self.value.row(), 0)

There are some conceptual problems with the given code.
First of all, the QtSql module should be preferred instead of artificially creating a model. For basic tables, QSqlTableModel is fine enough, while for custom queries, QSqlQueryModel is a good choice.
Now the problem is that UI-based selection is always based on visible items: if you select a row in a view that has hidden columns, you will not get the hidden indexes that belong to those columns.
In order to get the indexes (as in QModelIndex) of hidden columns on a table widget, the only way is the same for a table view: you need to access the model and get the index for the row, or you get the actual model index and then get the sibling (which is conceptually the same, as the underlying function does):
item = self.table.selectedItems()[0]
index = self.table.indexForItem(index)
firstRowIndex = index.sibling(index.row(), 0)
sqlIndex = firstRowIndex.data() # might be a string
Note that you can also use siblingAtColumn():
firstRowIndex = index.siblingAtColumn(0)
That's because when you create QTableWidget items, you're actually creating a new model, and the row for that model doesn't reflect the actual "row" of that index in the source model; items in the second row will return 1 for row(), even if their actual row is different, and that's because that item has been added as second to the table widget, since it's the second item in the query.
So, the solution is that you either get the incremental row value for the first column index sibling, or you use one of the predefined Sql models.
For simple models, the latter solution is fine enough, but if you need more complex models, the first is certainly more accurate and reliable.

Related

python3 psycopg SQL identifier must be string

I am trying to reference dynamic tables and fields in a tkinter GUI project using MySQLdb. Using psycopg2.sql to handle an insert statement.
The user select a code, size and color and inputs a quantity. The table names are made up of the size and the code (eg. size-small and code-1111, table_name=small1111). Then the color is the column name and the quantity is an integer entered into the field. The inputs are saved in a dictionary (tdict) when the user selects them. And the dictionary elements are called to be saved in the database table.
table_name = tdict['Size']+tdict['Code']
stmnt = ("INSERT INTO {} (%s, Date) VALUES(%s, %s)").format(sql.Identifier((table_name, tdict['Color'])))
c.execute(sql.SQL(stmnt, (tdict['Quantity'], date)))
The insert query is giving me a TypeError
TypeError("SQL identifiers must be strings")
Can anyone please help? What am I doing wrong? How should the Identifier be made to behave as a string?
Note: I've tried to pass the Identifier elements through a str class but it didn't work. ie
stmnt = ("INSERT INTO {} (%s, Date) VALUES(%s, %s)").format(sql.Identifier((str(table_name, tdict['Color']))))
You are asking sql.Identifier() to create an identifier out of a tuple, e.g. ('small1111','magenta'). Because format() only substitutes into braces {} (and not %s), I think what you actually had in mind was this:
stmnt = sql.SQL("INSERT INTO {} ({}, Date) VALUES(%s %s)").format( sql.Identifier(table_name), sql.Identifier(tdict['Color']) )
I'd suggest you rethink your database design, though --- you should probably have columns named size, code, and color rather than separate tables and columns for each. That will prevent you from having to add a new column each time a new color or a new table for each new size or code. SELECT count(*) FROM inventory WHERE size = 'small' AND code = '1111' GROUP BY color seems preferable to having to create queries dynamically.
This error message will also appear when you have a typo error where you should have used sql.Literal('someFixedNumber'), but instead using sq.Identifier('someFixedNumber')

Inserting data into database with python/sqlite3 by recognising the column name

I've got a problem that I don't know how to solve, I've tried many solutions but always getting that Operational error: near...
def insert_medicine_to_table():
con = sqlite3.connect('med_db3.db')
cur = con.cursor()
table_name = 'medicines'
column_name = "présentation"
value = 'Boîte de 2 seringues pré-remplies'
cur.execute("INSERT INTO medicines {} VALUES (?)".format(column_name), value)
con.commit()
con.close()
sqlite3.OperationalError: near "présentation": syntax error
The goal here is that either the script or python has to recognize the field (column name) and insert the value into "that" field, like the following:
fields = ['présentation', 'princeps', 'distributeur_ou_fabriquant', 'composition', 'famille', 'code_atc', 'ppv', 'prix_hospitalier', 'remboursement', 'base_de_remboursement__ppv', 'nature_du_produit']
values = ['Boîte de 2 seringues pré-remplies', 'Oui', 'SANOFI', 'Héparine', 'Anticoagulant héparinique', 'B01AB01', '43.80', '27.40', 'Oui', '43.80', 'Médicament']
That is one entry in the database. The problem here is that other entries can or not have one or more values for some field, and also the fields are not presented in the same order in other entries.
It has to recognize each field in the database table and insert each value into the right column.
The problem causing your error is that your SQL isn't valid. The statement you are trying to execute is:
INSERT INTO medicines présentation VALUES (?)
The statement you want to execute is:
INSERT INTO medicines ("présentation") VALUES (?)
As far as your larger question is concerned, if you create both the list of columns ("présentation") and list of parameter markers (?) and build the query using them, you're most of the way there.
If a field can have multiple values supplied for each "entry" in your database, you may need to change your database design to handle that. You'll at least need to figure out how you want to handle the situation, but that would be a matter for a different question.

Web2py: Incorrect row when representing a referenced field

It's rare that I find an issue that hasn't already be answered but I've been searching for this for 3 days and haven't found anything yet.
I'm aiming to create a page for inputing records in a 'spreadsheet' like format. I've used inline editing in SQLFORM.grid from this slice.
The problem I'm having is that when one of the fields is a reference to another table, the row being use in the lambda function is taking the row of the reference table rather than the row in the grid.
Here is an example:
Model
db.define_table('people',
Field('name', 'string'),
format = '%(name)s',
)
db.define_table('animals',
Field('name', 'string'),
Field('pet_owner', 'reference people'),
format = '%(name)s',
)
Controller
def index():
#process submitted form
if len(request.post_vars) > 0:
print request.post_vars
for key, value in request.post_vars.iteritems():
(field_name,sep,row_id) = key.partition('_row_')
if row_id:
db(db.animals.id == row_id).update(**{field_name:value})
db.animals.name.represent = lambda value,row: SQLFORM.widgets.string.widget(db.animals.pet_owner,value, **{'_name':'name_row_%s' % row.id})
db.animals.pet_owner.represent = lambda value,row: SQLFORM.widgets.options.widget(db.animals.pet_owner,value, **{'_name':'pet_owner_row_%s' % row.id})
grid = SQLFORM.grid(db.animals,
selectable= lambda ids : redirect(URL('animals',vars=request._get_vars)),
)
grid.elements(_type='checkbox',_name='records',replace=None) #remove selectable's checkboxes
return dict(grid=grid)
At first it appears that the grid is working correctly. However, when inspecting the drop-downs for the reference fields, if two consecutive rows have the same value (e.g. two animals with the same owner) the same row is used in the name (pet_owner_row_1) which means that the value being passed to process the submitted form is not an integer (e.g. 3) but as the integers separated by pipes (e.g. '|3|3|').
I've confirmed that this is where the issue is by changing the represent to
db.animals.pet_owner.represent = lambda value,row: row
which shows the exact same row data for different animals.
Here is an image showing the inspector on the form items: http://i.stack.imgur.com/oFtF8.png
How can I get the row id of the grid's row rather than the id of the reference?
Any help is greatly appreciated!
This is a bug that has recently been fixed in the master branch but not released yet. In the meantime, a workaround is to temporarily change the field to an integer type:
db.animals.pet_owner.type = 'integer'
db.animals.pet_owner.represent = lambda value,row: SQLFORM.widgets.options.widget(
db.animals.pet_owner,value, **{'_name':'pet_owner_row_%s' % row.id})

cannot set valid itemto QTableWidgetItem

I'm trying to populate two different QTableWidgets. For the first one it works find, but for the second one, it won't actaully set the items to the QTableWidget.
In the second, failing attempt, it does successfully create the item (both type(item) and item.text() work fine and return the correct values). However, when I try to add the item to the table, it says that table2.item(row, col) is NoneType. The rows and columns are created correctly before setting the item though.
working attempt:
item = QTableWidgetItem(self.fields[j].name())
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
table1.setItem(j,i,item)
failing attempt:
item = QTableWidgetItem(typ)
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
table2.setItem(row, col, item)
Neither can I see the difference between the two blocks, nor do I understand why it won't set the item to the TableWidget. Is there a geneal misunderstandng about how this works?

duplicated column name when using join with Zend_Db_table

I have two tables. Both of them have a column named 'title'. When I use the following code snippet to join two tables, I can't access one of the title column.
$select = $this->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
$select->setIntegrityCheck(false);
$select->join("service","service.id = lecture.service_id");
return $select;
is there a way to access both columns?
You need to rename one of the columns so it doesn't conflict with the other. If you pass an array as the optional 3rd argument to join(), you can specify which columns to retrieve from the joined table. If one or more of the entries in the array is hashed, then the hash key will be used as the property name. With the code below, you can refer to the title column of the service table as "service_title" in your query results. If you want other columns from the service table, add them to the array, with or without hashes as desired.
$select = $this->select(Zend_Db_Table::SELECT_WITH_FROM_PART);
$select->setIntegrityCheck(false);
$select->join("service", "service.id = lecture.service_id",
array("service_title" => "service.title");
return $select;
$select = $this->select();
$select->from(array('t'=>'table1'), array('table_title AS title_first','table_sendo_colun','table_third_colun'));
$select->setIntegrityCheck(false);
$select->join("service","service.id = t.service_id");
return $select;
Maybe It can do the job.
Regard´s.

Resources