Django: When to use QuerySet none()
Question:
Just came across this in the django docs
Calling none() will create a queryset that never returns any objects
and no query will be executed when accessing the results. A qs.none()
queryset is an instance of EmptyQuerySet.
I build a lot of CRUD apps (surprise) and I can’t think of a situation where I would need to use none()
.
Why would one want to return an EmptyQuerySet?
Answers:
Usually in instances where you need to provide a QuerySet
, but there isn’t one to provide – such as calling a method or to give to a template.
The advantage is if you know there is going to be no result (or don’t want a result) and you still need one, none()
will not hit the database.
For a non-realistic example, say you have an API where you can query your permissions. If the account hasn’t been confirmed, since you already have the Account
object and you can see that account.is_activated
is False
, you could skip checking the database for permissions by just using Permission.objects.none()
In cases where you want to append to querysets but want an empty one to begin with
Similar to conditions where we instantiate an empty list to begin with but gradually keep appending meaningful values to it
example..
def get_me_queryset(conditionA, conditionB, conditionC):
queryset = Model.objects.none()
if conditionA:
queryset |= some_complex_computation(conditionA)
elif conditionB:
queryset |= some_complex_computation(conditionB)
if conditionC:
queryset |= some_simple_computation(conditionC)
return queryset
get_me_queryset
should almost always return instance of django.db.models.query.QuerySet
(because good programming) and not None
or []
, or else it will introduce headaches later..
This way even if none of the conditions come True
, your code will still remain intact. No more type checking
For those who do not undestand |
operator’s usage here:
queryset |= queryset2
It translates to:
queryset = queryset + queryset
another use of queryset.none is when you don’t know if there will be objects but do not want to raise an error.
example:
class DummyMixin(object):
def get_context_data(self,**kwargs):
""" Return all the pks of objects into the context """
context = super(DummyMixin, self).get_context_data(**kwargs)
objects_pks = context.get(
"object_list",
Mymodel.objects.none()
).values_list("pk", flat=True)
context["objects_pks"] = objects_pks
It’s useful to see where qs.none()
is used in other examples in the Django docs. For example, when initializing a model formset using a queryset if you want the resulting formset to be empty the example given is:
formset = AuthorFormSet(queryset=Author.objects.none())
Another good use case for this is if some calling method wants to call .values_list()
or similar on results. If the method returned None, you’d get an error like
AttributeError: 'list' object has no attribute 'values_list'
But if your clause returns MyModel.objects.none()
instead of None
, the calling code will be happy, since the returned data is an empty queryset rather than a None object.
Another way of putting it is that it allows you to not mix up return types (like “this function returns a QuerySet or None,” which is messy).
none() is used in get_queryset() to return an empty queryset depending on the state of has_view_or_change_permission() as shown below:
class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
# ...
def has_view_or_change_permission(self, request, obj=None):
return self.has_view_permission(request, obj) or self.has_change_permission(
request, obj
)
# ...
class InlineModelAdmin(BaseModelAdmin):
# ...
def get_queryset(self, request):
queryset = super().get_queryset(request)
if not self.has_view_or_change_permission(request):
queryset = queryset.none() # Here
return queryset
Just came across this in the django docs
Calling none() will create a queryset that never returns any objects
and no query will be executed when accessing the results. A qs.none()
queryset is an instance of EmptyQuerySet.
I build a lot of CRUD apps (surprise) and I can’t think of a situation where I would need to use none()
.
Why would one want to return an EmptyQuerySet?
Usually in instances where you need to provide a QuerySet
, but there isn’t one to provide – such as calling a method or to give to a template.
The advantage is if you know there is going to be no result (or don’t want a result) and you still need one, none()
will not hit the database.
For a non-realistic example, say you have an API where you can query your permissions. If the account hasn’t been confirmed, since you already have the Account
object and you can see that account.is_activated
is False
, you could skip checking the database for permissions by just using Permission.objects.none()
In cases where you want to append to querysets but want an empty one to begin with
Similar to conditions where we instantiate an empty list to begin with but gradually keep appending meaningful values to it
example..
def get_me_queryset(conditionA, conditionB, conditionC):
queryset = Model.objects.none()
if conditionA:
queryset |= some_complex_computation(conditionA)
elif conditionB:
queryset |= some_complex_computation(conditionB)
if conditionC:
queryset |= some_simple_computation(conditionC)
return queryset
get_me_queryset
should almost always return instance of django.db.models.query.QuerySet
(because good programming) and not None
or []
, or else it will introduce headaches later..
This way even if none of the conditions come True
, your code will still remain intact. No more type checking
For those who do not undestand |
operator’s usage here:
queryset |= queryset2
It translates to:
queryset = queryset + queryset
another use of queryset.none is when you don’t know if there will be objects but do not want to raise an error.
example:
class DummyMixin(object):
def get_context_data(self,**kwargs):
""" Return all the pks of objects into the context """
context = super(DummyMixin, self).get_context_data(**kwargs)
objects_pks = context.get(
"object_list",
Mymodel.objects.none()
).values_list("pk", flat=True)
context["objects_pks"] = objects_pks
It’s useful to see where qs.none()
is used in other examples in the Django docs. For example, when initializing a model formset using a queryset if you want the resulting formset to be empty the example given is:
formset = AuthorFormSet(queryset=Author.objects.none())
Another good use case for this is if some calling method wants to call .values_list()
or similar on results. If the method returned None, you’d get an error like
AttributeError: 'list' object has no attribute 'values_list'
But if your clause returns MyModel.objects.none()
instead of None
, the calling code will be happy, since the returned data is an empty queryset rather than a None object.
Another way of putting it is that it allows you to not mix up return types (like “this function returns a QuerySet or None,” which is messy).
none() is used in get_queryset() to return an empty queryset depending on the state of has_view_or_change_permission() as shown below:
class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
# ...
def has_view_or_change_permission(self, request, obj=None):
return self.has_view_permission(request, obj) or self.has_change_permission(
request, obj
)
# ...
class InlineModelAdmin(BaseModelAdmin):
# ...
def get_queryset(self, request):
queryset = super().get_queryset(request)
if not self.has_view_or_change_permission(request):
queryset = queryset.none() # Here
return queryset