0

In the below example, I have questions.

Example

from django.utils.functional import cached_property

class Product(models.Model):
    class ProductType(models.TextChoices):
        PRODUCT = 'PRODUCT', _('Product')
        LISTING = 'LISTING', _('Listing')

    my_model = models.ForeignKey(MyModel, on_delete=models.CASCADE, related_name='products')
    product_type = models.CharField(max_length=7, choices=ProductType.choices)

class MyModel(models.Model):
    ...
    
    @cached_property
    def listing(self):
        return self.products.get(product_type=Product.ProductType.LISTING)

Questions

  1. Is the listing property being cached on the MyModel object? I ask because it's accessing .get() of a queryset which has greater implications.

Ex:

instance = MyModel()
instance.listing # hits db
instance.listing # gets from cache?
  1. How can I set up a scenario to inspect and verify that caching of instance.listing is in-fact happening? I read to look in the __dict__ method of instance.listing.__dict__ but I don't notice anything specific.
Jarad
  • 17,409
  • 19
  • 95
  • 154

3 Answers3

2

I awarded @Sardorbek Imomaliev with the answer for pointing me in the right direction. For clarity to anyone that stumbles across this question, here are my findings.

  1. Is the listing property being cached on the MyModel object? I ask because it's accessing .get() of a queryset which has greater implications.

Answer: yes. But, if the cached object's attributes change, these changes aren't visible in the cached object. Ex: if price changes from $4 to $5, the cached property will still show $4.

  1. How can I set up a scenario to inspect and verify that caching of instance.listing is in-fact happening?

Answer:

>>> inst = MyModel.objects.first()
>>> inst.__dict__.keys()
dict_keys(['_state', 'id', 'user_id', 'title', 'slug'])
>>> inst.listing
<Listing: Some Listing Instance>
>>> inst.__dict__.keys()
dict_keys(['_state', 'id', 'user_id', 'title', 'slug', 'listing'])
  1. Bonus: What does it look like if it's not a @cached_property but is just a regular @property?

Answer: 'listing' does not get added to inst.__dict__.

>>> inst = MyModel.objects.first()
>>> inst.__dict__.keys()
dict_keys(['_state', 'id', 'user_id', 'title', 'slug'])
>>> inst.listing
<Listing: Some Listing Instance>
>>> inst.__dict__.keys()
dict_keys(['_state', 'id', 'user_id', 'title', 'slug'])
Jarad
  • 17,409
  • 19
  • 95
  • 154
1

If you read source of this decorator https://docs.djangoproject.com/en/4.0/_modules/django/utils/functional/#cached_property you will see that you are probably checking this in wrong place. listing will be cached on the instance itself, meaning you need to check instance.__dict__.

Sardorbek Imomaliev
  • 14,861
  • 2
  • 51
  • 63
1

to delete the cached property,you can use del inst.listing.so you can basically use signals to delete this property cache whenever the Product model is changed

Dante
  • 165
  • 8