Often in views, one can find code that looks like:
from django.shortcuts import render
def some_view(request):
my_objects = MyModel.objects.values()
return render(request, 'some_template.html', {'my_objects': my_objects})
The .values(…)
[Django-doc]
part will return a (QuerySet
) of
dictionaries, not MyModel
objects.
Why is it a problem?
Dictionaries are less "rich". These simply map keys to values. A model enhances that with several extra functionalities:
- validation of fields;
- mapping the field to its representation with
get_fieldname_display
; - properties added on the model;
- retrieve related model objects
(
ForeignKey
s act like lazy queries); and - updating, removing, etc. of the model to the database.
These are typical problems that arise by the primitive obsession antipattern [refactoring.guru].
How can we fix this?
Do not make use of .values(…)
unless in certain circumstances. One can make
use of .values(…)
for example to group by a
certain value. But normally using .values()
is not a good idea, one thus better creates a query that
looks like:
from django.shortcuts import render
def some_view(request):
my_objects = MyModel.objects.all()
return render(request, 'some_template.html', {'my_objects': my_objects})
Extra tips
Sometimes people make use of
.values(…)
to boost
queries, by only selecting columns they are interested
in. One can make use of .only(…)
[Django-doc]
and .defer(…)
[Django-doc]
to retrieve only a subset of the columns of the model.
The remaining columns are then lazy loaded with
extra queries when necessary.
Some people use .values(…)
to
serialize data to a JSON blob. Usually it is
better to make use of serializers [drf-doc]
that are for example offered by the Django
REST framework package. These serializers allow to
serialize related model objects, can do more
sophisticated serialization, and often work in
both directions: converting a model object to a
serialized form, and deserializing objects into model
objects. This will thus reduce the amount of work and do
proper validation.