ORMs
Every model in Django has an attribute called objects. Take a simple views.py file for instance
from store.models import Product
Product.objects #the model product has an attribute modelsThe Products.objects returns a manager object. A manager object is like an interface to the database. It’s like a remote control and a bunch of buttons you can use to talk to our database.
As such, there are also a bunch of methods for querying data. For instance
Product.objects.all()Product.objects.get()Product.objects.filter()Most of these methods return a queryset. So when you call the method, you dont get a list of Products but a queryset object. A QS object is an object that encapsulates a query.
So at some point, Django is gonna evaluate that queryset and then this when Django will generate the right sql statement to send to our db. It only happens under some circumstances, for eg: When you iterate over a query set. See below
query_set = Product.objects.all()
for product in query_set: print(product)When you navigate to the SQL section in the Debug Toolbar, you will see the sql commands that have been run.
Another scenario is when you convert the query_set into a list.
list(query_set)Another scenario is when you access an element. for eg: an individual element or slice it.
list(query_set)Because of this, we say querysets are lazy. Why is that so? Why is is that when we run the Product.objects.all() method Django doesnt automatically call the db. This is because we can use querysets to build more complex queries.
For instance, if we call
query_set.filter()It is going to return a whole new query_set.
You can do
query_set.filter().filter()to further filter the result. which returns another query
and also
query_set.filter().filter().order_by()to further order it
So by chaining all those methods together, you build a complex query, and at some point when we perform an action like converting it into a list and iterating the list, that query will be evaluated.