Skip to content

Conversation

efrederickson
Copy link
Contributor

Overview

When running a queryset like this:

values = set()
for results in MyModel.objects.filter(Q(a__subfield=1) | Q(b__subfield=1)).values_list("a__subfield", "b__subfield"):
    values.update(results)

Over documents like this:

{"a": {"subfield": 1}, "b": {"subfield":1}},
{"a": {"subfield": 1}, "b": null},
{"a": {"subfield": 1}, "b": {"subfield":1}}

The method _get_scalar will raise an AttributeError on getting the attribute subfield of the second document where b is null.

The workaround currently is to instead do a values_list on (a, b) and then perform null checks on the client side, like this, which is much more verbose (assume get_value is a helper function roughly equivalent to getattr):

values = set()
for (a_par, b_par) in MyModel.objects.filter(Q(a__subfield=1) | Q(b__subfield=1)).values_list("a", "b"):
    if a_par:
       values.add(get_value(a_par, "subfield"))
    if b_par:
       values.add(get_value(b_par, "subfield"))
    ...

This is also less efficient as the whole embedded document must be fetched from the database instead of just the two desired fields. A similar solution using only could be utilized but it is also less elegant.

Fix

Add a simple null check into the _get_scalar method on BaseQuerySet, so that it returns None instead of raising an exception.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant