class User(models.Model):
name = Charfield(...)
age = Integerfield(...)
...
class Article(models.Model):
user = ForeignKey(User, ...)
title = Charfield(...)
content = Charfield(...)
...
class ArticleView(ViewSet):
...
queryset = Article.objects.all().select_related('user')
queryset = Article.objects.all().prefetch_related('user')
class ArticleSerializer(ModelSerializer):
class Meta:
model = Article
fields = "__all__"
1. If I just apply select_related (or prefetch_related), will the user's information be added to my query set?
2. If so, when serializing the data, the information of the user who innerjoined through select_related is not shown in the serializer.data returned after serialization.
2-1. If I had to write additional code on my serializer, Which of the following options should I use?
class ArticleSerializer(ModelSerializer):
class Meta:
model = Article
fields = "__all__"
depth = 1
or
class ArticleSerializer(ModelSerializer):
user = UserSerializer()
class Meta:
model = Article
fields = "__all__"
2-2. The above options can get the same user's information without selecting_related(or prefetch_related), so why do you use select_related(or prefetch_related)?
Is there a difference in the number of DB lookup?
Yes, select_related
will make a join query and fill user
attribute with an User
instance. Without select_related
, when you access user
attribute, a extra query will be made to get User
instance.
Returns a QuerySet that will “follow” foreign-key relationships, selecting additional related-object data when it executes its query. This is a performance booster which results in a single more complex query but means later use of foreign-key relationships won’t require database queries.
prefetch_related() is used for many-to-many and many-to-one relationship.
prefetch_related, on the other hand, does a separate lookup for each relationship, and does the ‘joining’ in Python. This allows it to prefetch many-to-many and many-to-one objects, which cannot be done using select_related, in addition to the foreign key and one-to-one relationships that are supported by select_related.
Because default serializer field for ForeignKey
is PrimaryKeyRelatedField
which represent the target of the relationship using its primary key.
Refer to ModelSerializer document.
Any relationships such as foreign keys on the model will be mapped to PrimaryKeyRelatedField. Reverse relationships are not included by default unless explicitly included as specified in the serializer relations documentation.
2-1. If I had to write additional code on my serializer, Which of the following options should I use?
depth=1
is equal to define a nested model serializer with fields='__all__'
for all ForeignKey
and OneToOneField
. So in your case, 2 serializers are same.
Refer to source code
def build_nested_field(self, field_name, relation_info, nested_depth):
"""
Create nested fields for forward and reverse relationships.
"""
class NestedSerializer(ModelSerializer):
class Meta:
model = relation_info.related_model
depth = nested_depth - 1
fields = '__all__'
field_class = NestedSerializer
field_kwargs = get_nested_relation_kwargs(relation_info)
return field_class, field_kwargs
2-2. The above options can get the same user's information without selecting_related(or prefetch_related), so why do you use select_related(or prefetch_related)?
You shuld use prefetch_related
, because it use one query to fetch Article
s and User
s. Say you have 100 articles, if you don't use prefetch_related
, 100 extra query will be made when you access article.user
.
Summary, serializer serialize data according to the fields defined by you, not according to the fields fetched in the queryset. ModelSerializer
have default serializer fields for all the model fields, if the default serializer fields are not what you want, you should define serializer fields explicitly.