3 ms·
> Regarding 1. While this is certainly an issue, it’s an issue for anyone using any framework and a challenge of database-backed web applications everywhere. N
by yxhuvud 5y ago
> Regarding 1. While this is certainly an issue, it’s an issue for anyone using any framework and a challenge of database-backed web applications everywhere.
No, there are frameworks out there that doesn't allow queries during template rendering. See Lucky for an example, https://luckyframework.org/ https://luckyframework.org/.
- Nextgrid 5y agoThe problem is not whether the queries are ran in templates or in code, it's which queries are ran. Doing the same he did in the template but in code (by constructing a dictionary of items to be passed to the template) will have exactly the same problem. The solution of using eager loading has nothing to do with whether you run your query in the template or in code.
- jmconfuzeus 5y agoIt's easier to notice expensive SQL queries in the view vs in the template. Anyone who claims that it's fine to run queries in templates has smoked something really good. Personally, I'll continue to aggregate all my data using JOINs before presenting them.
- Nextgrid 5y agoWhen it comes to "queries" keep in mind that I'm not saying you should call "Model.objects.filter(...)" in the template (in fact that would be very difficult to do unless you pass a "Model" reference to the template). You still do that in code. However due to how Django handles queries by default, calling the ORM won't actually execute the query until the queryset is evaluated in most cases (unless requesting a single object or doing an aggregation), so your queries are still technically "ran" from the template - even if you are doing prefetch_related. I personally don't have a problem with that; explicitly casting the queryset to a list before rendering a template seems like unnecessary boilerplate and still doesn't actually isolate you from the "N+1" queries problem if your template then accesses an object's relation that hasn't been prefetched.
- jmconfuzeus 5y agoThat's the point. Instead of worrying about whether you're accessing a related attribute, join everything and evaluate the QuerySet before passing it to context. You'll never have to worry about whether {{ pizza.topping.name }} is hitting the database ever again, especially, if you install django-zen-queries because it will raise an exception if you try to.
- Nextgrid 5y agoGot it - so the magic here isn't merely to evaluate querysets ahead of time (which can still return objects with unfetched relations that'll cause a query at runtime if accessed) but to also rely on the third-party package to explicitly disallow that.
- jmconfuzeus 5y agoIt's highly unlikely that will you execute unnecessary queries from view code because usually you'll have a context like {"pizzas": page_obj.object_list}. You'll almost never execute something like: for pizza in pizzas: print(pizza.topping.name) But you'll certainly do the following in templates: {% for pizza in pizzas %} <p>{{ pizza.topping.name }}</p> {% endfor %} I also don't understand why you want to avoid 3rd party packages, especially if it helps you write better code.
- Nextgrid 5y agoMy argument was that the third-party package is what's key here. Merely converting your querysets to a list in code before handing it off to the template won't fully protect you against extra queries. I'm not necessarily trying to avoid third-party packages, in fact I've installed the package you suggested in one of my projects and will be trying it out.