class Course(models.Model):
name = models.CharField(max_length=50)
class Module(models.Model):
course = models.ForeignKey(Course, related_name='modules')
name = models.CharField(max_length=50)
class Meta:
order_with_respect_to = 'course'
I want to make a function that return the course last module id but the related course.modules maybe prefetched or no, so this function would be like.
If Django has loaded data for a view, all future references for that data will pull what has already been retrieved.
On top of that PostgreSQL (among others) maintains their own cache, such that multiple identical queries don’t necessary need to retrieve data from disk.
Unless you’ve got a specific, identified issue where this is a problem, this generally isn’t worth worrying about. (And, if you are in a situation where this is a problem, there are generally other issues you want to address first.)
If Django has loaded data for a view, all future references for that data will pull what has already been retrieved.
If a do these queries
course = Course.objects.get(pk=1)
# and
course = Course.objects.pretetch_related('modules').get(pk=1)
The 2nd has already their related modules in cache, so if i need to know the last module id, i must be use this modules on cache instead of making another query.
In the 1st i don’t have the related modules, so i make another query that only retrieve the data that i need, instead to bring all objects to memory.
I’m trying to write a model method that handle both cases and i think a i need to know if the course has already their modules on cache or not.
You don’t write models methods for this. The retrieval of data is handled within either your views or a Model Manager. A model method should simply refer to the function necessary to retrieve the latest module it.
If you’re writing a view that doesn’t need the last module id, you write the first query you posted.
If you’re writing a view that does, then your view uses the second query.
Keep in mind that all view invocations are independent of each other. When view “X” refers to model “A”, then view “Y” also refers to model “A”, they are most likely going to be different instances of model “A”. These model instances do not have a “life of their own” outside the invocation of a view.
If you’re writing a view that doesn’t need the last module id, you write the first query you posted.
If you’re writing a view that does, then your view uses the second query.
Yeah, that’s exactly how it works currently, but I’m trying refactor that behavior. Maybe I change that method to a utility or just leave it as it is.
The python zen says
There should be one-- and preferably only one --obvious way to do it.
So I’m trying to make a only one way to retrieve the last course module id, regardless if the instance has or not those related objects in memory.
The question in the first place was if how can I check if related objects has been prefetched or no. I searched in the documentation and seems that does not exist a way to accomplish that. I appreciate the code recommendations but that’s not what the topic is about.
Yes. Work with Django and not against it. You’re trying to refactor into a pattern contrary to what roughly 15 years of Django architecture has built.
That’s a nice option, maybe I change to that form or, instead to declare a @property, I can use a model method or utility function with a bool arg to say if the related objects are in cache or not.
I read the prefetch_related documentation again and see that use .latest() on a prefetched queryset produce another hit to the database, so the above method for the example can be
self.modules.all()[len(self.modules.all())-1].pk
That doesn’t hit the database again.
Now, if a do self.modules.all().latest().pk, brings to memory all model values, and that’s not what a want, as it django optimization says, I should only retrieve the data that I need. For the example, I only need the last module pk, if the modules are in memory, simple do it a loop until the last, else, do it a queryset that only retrieve de last module pk.
What I wanted to know is if exists a option like self.related_set.loaded() that return a bool and seems that not exists.
That is not an accurate statement. You can verify a couple different ways that it does not necessarily invalidate the prefetched queryset and does not result in an extra query, beyond the original second query required by the prefetch_related.