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

J Barchan jnbarchan at gmail.com
Thu Feb 7 08:44:56 GMT 2019


On Wed, 6 Feb 2019 at 22:27, Maurizio Berti <maurizio.berti at gmail.com>
wrote:

> 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
>

Hi Maurizio,

Thank you for all the time you have spent on this!  We'd better wrap it up,
as at the end of the day although I got confused & stuck when I first tried
it I do have an acceptable workaround for sorting of storing
QDate(python_date) instead of the normal plain python_date in the model,
which will do me in this instance.

Nope :-)
> Any kind of object can be assigned to a (any) DataRole to a valid
> QModelIndex.
>

I suspect this is the key to my misunderstanding.  When I pass a Python
datetime to some PyQt function which expects a QDate (I can't think of
one), or a Python decimal.Decimal where PyQt/Qt function expects a float,
they get auto-converted, right?  But when I pass those to, say,
QStandardItemModel.setData(), you are saying there is no conversion and the
Python object is stored as-is, right?  And when
QStandardItemModel.sort()/lessThan() comes along and looks at the data
which is a Python datetime or Decimal type, this does not count as the same
situation (e.g. explicit argument to function) where PyQt would
auto-convert as necessary --- quite possibly because we are down in C++ Qt
code by then which knows nothing about Python --- so it fails.  Is that
about right?

Many thanks.


-- 
Kindest,
Jonathan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20190207/7fa8bbb4/attachment.html>


More information about the PyQt mailing list