[PyQt] QSortFilterProxyModel::sort() not sorting on column types

Maurizio Berti maurizio.berti at gmail.com
Wed Feb 6 22:25:43 GMT 2019


Il giorno mer 6 feb 2019 alle ore 16:27 J Barchan <jnbarchan at gmail.com> ha
scritto:

> Think of this.  When I go model.setData(row, col, python_date), the C++
> definition for setData() takes a QVariant for the value.  Somewhere along
> the line, PyQt auto-converts Python datetime.date to a QVariant of type
> QMetaType::QDate containing a QDate, right?  (And similarly unwraps if I
> call model.data(row, col).)  At least that's my understanding.
>

Nope :-)
Any kind of object can be assigned to a (any) DataRole to a valid
QModelIndex. I don't know how it works on C++ specifically (I think it
doesn't change that much), but in the PyQt world whenever you setData()
with a Python object as argument, the object remains intact and is stored
in the model as it is, despite the type of the object itself (or, probably,
a "PyQtObject" as it was called for PyQt4 and SIP version 1, which probably
is a special PyQt "variant" of QVariant, but I'm just guessing here -
anyway, it's returned in its original form when accessed).
The conversion to a Qt type is only done whenever it's needed, and is
usually automatic and transparent to the Python interface.


Meanwhile, that doc states it can also handle QMetaType::QString.  QString
> is also a Qt type, not a Python one.  But I don't bother to put QStrings
> into my model, I just put in plain Python strs, *and yet I find that
> those do sort*.  Why is that OK but the date ones not?
>

If you use SIP v2 (which is default on PyQt5, but can be set for PyQt4 as
well as with other compatible types) the QString class is not available.
You cannot even import it, as it doesn't exist at all: PyQt automatically
treats all strings as QStrings and viceversa as it's done with numeric
values - this means that Python strings "are" QStrings. Other and more
"complex" object types are automatically converted whenever it's needed,
but they original state is maintained, so a Python datetime is NOT a
QDateTime, but can be used as it would.
While it can be a small issue (as some useful QString processing methods
are obviously not available), it's a huge advantage since you don't have to
convert everytime between Qt and Python objects. The standard SIPv1 mode of
python objects in PyQt4 was a continuous headache, as you'd have always
needed to use the toPyObject() conversion, also creating issues with the
annoying differences and issues between Python 2's str and unicode types
and conversions.
So, long story short, the sort() of strings works just because Python
strings are "virtually" QStrings.


To make it even more confusing.  The above doc link for
> SortFilterProxyModel::lessThan() states:
>
> Any other type will be converted to a QString
>> <http://doc.qt.io/qt-5/qstring.html> using QVariant::toString
>> <http://doc.qt.io/qt-5/qvariant.html#toString>().
>>
>
I think that, from the PyQt point of view, this means that it converts the
object to a string only if the object is a known QVariant type that can be
converted to a "QString". I'm not really sure about this, but I'm assuming
this from the fact that other non-Qt objects are not converted to strings
in models even when required (for example, displaying data in an item
view), even if they do have a __str__() magic method implemented.
Interestingly enough, the public toString() method of QVariant is not
available on PyQt5 and cannot implemented therefore to create custom
QVariant classes.


I therefore thought if my native Python datetime.date was "not recognised",
> it would at minimum do a string sort.  Might not be what I intended for my
> dates, but at least I'd see something happening in the way of reordering.
> Instead, I see nothing gets moved, the original order is simply preserved,
> just as though for whatever reason the sort has done nothing.  No
> complaints, just nothing happens.
>

Considering what explained before, you might agree that lessThan() cannot
do any kind of sorting with "unknown" PyQt objects. It gets an unknown
object, doesn't "know" how to sort it against another (even similar)
object, then it leaves the order unsorted.


Thanks for your time!
>

Thank you! Actively thinking about these problems helps having a better
consciousness about how (PyQt) objects actually work. :-)

Maurizio

-- 
È difficile avere una convinzione precisa quando si parla delle ragioni del
cuore. - "Sostiene Pereira", Antonio Tabucchi
http://www.jidesk.net
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190206/b7a5ff57/attachment.html>


More information about the PyQt mailing list