On 1/28/06, Luke Plant <[EMAIL PROTECTED]> wrote:
> As Robert pointed out before, you usually don't have to worry about
> resetting the cache, since the objects will get GC after the template
> and views stop using them.  However, the Article.objects manager is
> special, since it is rooted in a class, and that's going to persist,
> isn't it?  So any iteration of Article.objects will cause the entire
> table to be read and kept in memory.
>
> You could say - "if there are no 'where clause' params added, then don't
> cache", but this wouldn't work for custom managers e.g.
> Articles.goodarticles = Articles.objects.filter(score_gt=50), since they
> would persist too.
>
> One solution would be to have managers not cache by default, but you
> could call Articles.objects.with_cache(True) to get an instance with
> caching turned on.  Related object lookups would always do that.

I've finally wrapped my brain around this problem, and it's a tricky
one. A common idiom is to do this in a view:

    def some_view(request):
        person_list = Person.objects
        return render_to_response('foo/person_list', {'person_list':
person_list})

As Luke mentioned, we cannot cache the result of Person.objects,
because the class persists. (The next time somebody does
Person.objects, he will get the result of the cache, which is not what
we want.)

But we *do* want caching, because if we don't have it in this case, it
will do a separate database query each time person_list is iterated
over. That's not good, either.

The goal is: Only one database query, and no persistent caching across
accesses to Person.objects.

One way to solve this problem would be to require people to use list():

    def some_view(request):
        person_list = list(Person.objects)
        return render_to_response('foo/person_list', {'person_list':
person_list})

But that's a horrible hack, IMO, and it's would be hard to explain to
new Django users why they'd need to do that.

This comes back to the Person.objects.all() thing that I'd mentioned
earlier. With all(), there's no strange special-case behavior.
Person.objects.all() would return a cache-filled object, and there
wouldn't be a need for a QuerySet to know whether it could accept
caching or not.

    def some_view(request):
        person_list = Person.objects.all()
        return render_to_response('foo/person_list', {'person_list':
person_list})

This would further simplify things by making a Manager's methods
*return* QuerySets instead of having a Manager *be* a QuerySet. The
downside is it's slightly more typing to do Person.objects.all() than
Person.objects -- but that's the only downside I see. Thoughts?

Adrian

--
Adrian Holovaty
holovaty.com | djangoproject.com | chicagocrime.org

Reply via email to