Joseph Kocherhans wrote: > Ian Bicking has kept len() out of SQLObject result sets even though it > seems really intuitive to use. Here's a rundown of what I remember > about his argument: __len__ would run "count (*)" against the db. I > think iter() calls len() implicitly for performance reasons, so you'd > be running a useless count(*) every time you started iterating over a > Query object.
OK, I think I have tracked this down - or a related issue. This is relevant whether we go with __len__ or not. If you have this view code (updated for the new syntax): context['articles'] = Article.objects # or Article.objects.all() And this template (exactly as before the syntax change): {% if articles %} {% for article in articles %} .. {{ article }} {% endfor %} {% else %} Sorry, no articles {% endif %} With the new syntax method, you never get the 'Sorry no articles', because Article.objects evaluates to true. This would be a bug with the new syntax. However, if Article.objects or Articles.objects.all() has a __len__ method as I proposed, then bool() will call it and return false if the answer is zero. So the above code would work, but do two db lookups, one for a count and the other for a list, which is also different from before, and is a performance bug. (NB I think this is 2.3/2.4 related - apparently the behaviour of bool(iter([])) changed.) One way around it would be to add __nonzero__ to the Query instance (I think), which would get and cache the list of objects, ready to be iterated. This would be slightly subtle behaviour, but something like this needs to be done. So you would have: bool(Article.objects) # retrieves list iter(Article.objects) # retrieves list len(Article.objects) # does count(*) Luke