Being new to Django, I’m starting to care a bit about performance of my web application.
I’m trying to transform many of my custom functions / properties which were originally in my models to querysets within custom managers.
in my model I have:
class Shape(models.Model): @property def nb_color(self): return 1 if self.colors=='' else int(1+sum(self.colors.upper().count(x) for x in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')) def __str__(self): return self.name + "-" + self.constraints @property def image_url(self): return format_html(f'{settings.SVG_DIR}/{self}.svg') @property def image_src(self): return format_html('<img src="{url}"|urlencode />'.format(url = self.image_url)) def image_display(self): return format_html(f'<a href="/static/SVG_shapes/{self}">{self.image_src}"</a>')
But I’m not clear on a few points:
1/ is there any pros or cons declaring with the propriety decorator in a django model?
2/ what is the cost of calling a function/property in term of database calls
and therefore, is there an added value to use custom managers / querysets and define annotations to simulate my functions at that level?
3/ how would you suggest me to transform my image & nb_color functions into annotations
Thanks in advance
PS: For the image related functions, I mostly figured it out:
self.annotate(image_url = Concat(Value(join(settings.SVG_DIR,'')), F('fullname'), Value('.svg'), output_field=CharField()), image_src = Concat(Value('<img src="'), F('image_url'), Value('"|urlencode />'), output_field=CharField()), image_display = Concat(Value('<a href="'+ settings.SVG_DIR+'/'), F('fullname'), Value('.svg">'),F('image_src'), Value('</a>'), output_field=CharField()), )
I am however having an issue for the display of image_src through:
readonly_fields=['image'] def image(self, obj): return format_html(obj.image_src)
it doesn’t seem to find the image while the adress is ok.
If anybody has an idea…
Advertisement
Answer
With now 1.5 years more experience, I’ll try to answer my newbie questions for the next ones who may have the same questions poping into their minds.
1/ is there any pros or cons declaring with the propriety decorator in a django model?
No cons that I could see so far.
It allows the data to be retrieved as a property of the model (my_shape.image_url
), instead of having to call the corresponding method (my_shape.image_url()
)
However, for different purposes, one my prefer to have a callable (the method) instead of a property
2/ what is the cost of calling a function/property in term of database calls
No extra calling to the database if the data it needs as input are already available, or are themselves attributes of the instance object (fields / properties / methods that don’t require input from outside the instance object)
However, if external data are needed, a database call will be generated for each of them.
For this reason, it can be valuable to cache the result of such a property by using the @cached_property
decorator instead of the @property
decorator
The only thing needed to use cached properties is the following import:
from django.utils.functional import cached_property
After being called for the first time, the cached property will remain available at no extra cost during all the lifetime of the object instance, and its content can be manipulated like any other property / variable:
and therefore, is there an added value to use custom managers / querysets and define annotations to simulate my functions at that level?
In my understanding and practice so far, it is not uncommon to replicate the same functionality in both property & managers
The reason is that properties are easily available when we are interested only in one specific object instance, while when you are interested into comparing / retrieving a given property for a range of objects, it is much more efficient to calculate & annotate this property for the whole queryset, for instance through using model managers
My give-away would be: For a given model, (1) try to put all the business logic concerning a single object instance into model methods / properties (2) and all the business logic concerning a range of objects into model managers
3/ how would you suggest me to transform my image & nb_color functions into annotations
Already answered in previous answer