I have a custom user profile model. This model has can_edit property that uses ContentType and Permission objects to determine if the user has permission or not. I'm using this property within serializer and it works fine, but is terribly inefficient, as per each user the ContentType and Permission are queried again.
It seems like prefetch_related could fit here, but I don't know how to apply it, as these objects are not referenced directly through some properties, but kinda queried separately. Is it possible to fetch the ContentType and Permission beforehand and just use the results in further queries?
Here's my model:
class CustomProfile(models.Model):
user = models.OneToOneField(User, related_name="profile", on_delete=models.CASCADE)
@property
def can_edit(self):
content_type = ContentType.objects.get_for_model(Article)
permission, _ = Permission.objects.get_or_create(
codename="edit", name="Can edit", content_type=content_type
)
return self.user.has_perm(self._permission_name(permission))
def _permission_name(self, permission):
return f"{permission.content_type.app_label}.{permission.codename}"
My current query:
User.objects.order_by("username").select_related("profile")
My serializer:
class UserSerializer(serializers.ModelSerializer):
can_edit = serializers.ReadOnlyField(source="profile.can_edit")
class Meta:
model = User
fields = (
"id",
"username",
"first_name",
"last_name",
"is_active",
"is_staff",
"can_edit",
)
In fact, I have more than one property with similar content to can_edit, so each user instance adds around 6 unnecessary queries for ContentType and Permission.
How can I optimize it?
can_edit" On thisUserSerializerclass or some other class? @Djent