पाठ 15 / 26
QuerySets: Filtering and Laziness
Chainable, lazy queries.
filter, exclude, get, lookups
A QuerySet represents a query; methods like filter, exclude, order_by and values_list return new QuerySets without touching the database. The query runs when you iterate, slice with a step, call list, count, exists or get. Field lookups use double underscores (price__lt, category__name), including across relations. get returns exactly one object or raises DoesNotExist or MultipleObjectsReturned.
Expressive, lazy, efficient
QuerySets build SQL lazily; select_related, aggregation and F expressions keep queries efficient.
Building and running queries, run
I ran this script with python manage.py shell --no-imports in the demo project (Django 6.1.1, SQLite). The filter builds SQL without running it (the WHERE clause is printed, with the model's default ordering); iterating runs it. get returns one product, a lookup across the relation finds in-stock Home products, and exclude counts one product out of stock.
from decimal import Decimal
from catalog.models import Category, Product
Product.objects.all().delete(); Category.objects.all().delete()
office = Category.objects.create(name="Office")
home = Category.objects.create(name="Home")
Product.objects.bulk_create([
Product(category=office, name="Pen", price=Decimal("899")),
Product(category=office, name="Notebook", price=Decimal("120")),
Product(category=home, name="Lamp", price=Decimal("1499")),
Product(category=home, name="Mug", price=Decimal("250"), in_stock=False),
])
qs = Product.objects.filter(price__lt=1000) # lazy: no query yet
print("SQL:", str(qs.query).split(" WHERE ")[1])
print([p.name for p in qs]) # the query runs here
print(Product.objects.get(name="Lamp"))
print(Product.objects.filter(category__name="Home", in_stock=True).values_list("name", flat=True)[:])
print(Product.objects.exclude(in_stock=True).count(), "out of stock")
Output:
SQL: "catalog_product"."price" < 1000 ORDER BY "catalog_product"."name" ASC ['Mug', 'Notebook', 'Pen'] Lamp (1499.00) <QuerySet ['Lamp']> 1 out of stock
Use exists() and count() wisely
exists() is cheaper than fetching rows just to check presence; avoid len(qs) when you only need a count.
त्वरित जाँच: When does a QuerySet hit the database?
- When it is evaluated, for example iterated, listed, counted or fetched with get
- When filter() is called
- When the model is imported
- Never
Answer
When it is evaluated, for example iterated, listed, counted or fetched with get — QuerySets are lazy.