[PyQt] PyQt 5.7, QSqlQueryModel.data() sub-classed override bug?

J Barchan jnbarchan at gmail.com
Wed May 16 11:27:57 BST 2018

On 10 May 2018 at 12:34, Phil Thompson <phil at riverbankcomputing.com> wrote:

> On 10 May 2018, at 11:31 am, J Barchan <jnbarchan at gmail.com> wrote:
> >
> > ​Hi Phil,
> >
> > Sorry, but I have one more related question about surprise behaviour.  I
> will try to keep this as brief as possible.
> >
> > Yesterday I came to understand why overriding, say,
> QSqlTableModel.data() came to grief on database-NULL, because of the Python
> loss of distinction on the QVariants representing ​"null" versus
> "default/invalid".  I would get back the "default" value where I expected
> the "null" value.
> >
> > In sorting my code out now in that light, I began to assume that
> QSqlTableModel.setData(index, None) would effectively suffer from exactly
> the same problem, in the opposite direction, i.e. it would set it to the
> "default" value not the "null" one.  And so I would need to deal with too.
> >
> > However, I find that, whether I do or do not override (in similar
> fashion) QSqlTableModel.setData(index: QModelIndex, value: QVariant)  ​it
> does set the value to database-NULL when called via .setData(index, None).
> >
> > This surprises me, as I expected it to have the same QVariant conversion
> issue over None as data(index) would.  Would you care to explain why this
> does not appear to be the symmetrical problematic case?
> Despite what the docs say, None is converted to an invalid QVariant rather
> than a null QVariant. I don't know what Qt does when given an invalid
> QVariant.
> Phil

​Dear Phil,

I previously wrote that I had had to give up on overriding
QSqlQueryModel.data() because​ none of the solutions we discussed
(concerning return type of native Python type versus QVariant type) worked
acceptably for me.  I have since discovered that, for various reasons, I *have
to* provide a Python override of that method.

I have revisited this issue, and have come up with a solution which *seems*
to work in all cases but which we did not propose between the two of us.

*Reminder of problems*:

   1. *Without* the sip.enableautoconversion(QVariant, False) call,
   overridden QSqlQueryModel.data() definition, at least when called on
   database NULL value for role DisplayRole, would return a "default" value
   string like 0 or '', which is wrong (I need blank/empty).
   2. *With* the sip.enableautoconversion(QVariant, False) call, and
   returning the QVariant as-is, solved the above case perfectly but meant
   that Python callers of the method would need to be changed to call
   QVariant.value() on the return result to behave as before now, which is
   not at all good for the existing code I have inherited.

There did not seem to be an alternative which just "worked" for me. * I
have now come up with the following override code*:

def data(self, item: QtCore.QModelIndex, role: QtCore.Qt.ItemDataRole
= QtCore.Qt.DisplayRole):
    was_enabled = sip.enableautoconversion(QtCore.QVariant, False)
    v = super().data(item, role)
    sip.enableautoconversion(QtCore.QVariant, was_enabled)
    if not v.isValid() or v.isNull():
        return None
        return v.value()

Note how:

   - In the invalid or NULL cases, it explicitly returns Python native None.
   That is *instead of* v.value(), which would have returned 0 or ''.  *This
   solves Problem #1 above*.
   - In the valid, non-NULL case, it returns QVariant.value(), i.e. native
   Python type, keeping Python callers unchanged.  *This solves Problem #2

Would you kindly comment whether you agree this definition is acceptable?
Do you see any pitfalls, or need to change any code here (e.g. based on
role value)?  I can only say that I have tried running with this, and am
finding all the cases I can see are working correctly/as desired, but
cannot be sure there is a case I have not thought of....

I'd *really* appreciate your feedback on this (hoping you'll agree with
me!!), thank you.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://www.riverbankcomputing.com/pipermail/pyqt/attachments/20180516/62759040/attachment.html>

More information about the PyQt mailing list