Typorithm · easy

Querysets, filtering and evaluation

pythondjangoindependent-practice
Saved on this device
Full lesson · 4 learning steps Open any exercise for focused practice
1

Step 1 of 4 · intro card

Querysets, filtering and evaluation

0%

Concept and contract

Select one explicit population, order it deterministically and observe when a queryset actually executes.

A queryset describes database work and usually does not execute it immediately when constructed. Filtering, ordering and evaluation are separate operations.

This lesson selects current fictional roles in one country, then returns identifiers in an explicit order. Country and active state belong to the same inclusion rule. Creating a second queryset with similar code does not automatically reuse the first queryset’s already evaluated result cache.

Mechanism and worked example

The helper seeds controlled rows and constructs one filtered, ordered queryset.

The helper seeds controlled rows and constructs one filtered, ordered queryset. Iterating it once performs the query and populates that queryset’s result cache; iterating the same object again reuses those results.

CaptureQueriesContext records the actual SQL observations around evaluation. The returned comparison shows that the two passes see the same identities, while the query count distinguishes reuse from a second independently executed query.

Complete worked example

python

from bootstrap_lab import django_setup
django_setup(__name__)

from bootstrap_lab import install_models
from django.db import models, connection
from django.test.utils import CaptureQueriesContext

class Role(models.Model):
    title = models.CharField(max_length=80)
    country = models.CharField(max_length=2)
    active = models.BooleanField(default=True)
    class Meta:
        app_label = "framework_lab"

install_models(Role)

def selected_ids(rows, country):
    Role.objects.all().delete()
    Role.objects.bulk_create([Role(**row) for row in rows])
    queryset = Role.objects.filter(country=country, active=True).order_by("id")
    with CaptureQueriesContext(connection) as observed:
        ids = [role.id for role in queryset]
        again = [role.id for role in queryset]
    return {"ids": ids, "same": ids == again, "queries": len(observed)}
Reasoning
The helper seeds controlled rows and constructs one filtered, ordered queryset. Iterating it once performs the query and populates that queryset’s result cache; iterating the same object again reuses those results.

Counterexamples and common mistakes

The counterexample clones the queryset with all before the second iteration.

The counterexample clones the queryset with all before the second iteration. The identities remain correct, but the second object causes another SQL query.

An output-only test would miss that difference. Do not confuse queryset result caching with a cross-request Redis cache or permanent freshness guarantee. Updating database state elsewhere does not automatically make an already evaluated queryset represent the latest state of the whole application.

Counterexample: a runnable framework mistake

python

from bootstrap_lab import django_setup
django_setup(__name__)

from bootstrap_lab import install_models
from django.db import models, connection
from django.test.utils import CaptureQueriesContext

class Role(models.Model):
    title = models.CharField(max_length=80)
    country = models.CharField(max_length=2)
    active = models.BooleanField(default=True)
    class Meta:
        app_label = "framework_lab"

install_models(Role)

def selected_ids(rows, country):
    Role.objects.all().delete()
    Role.objects.bulk_create([Role(**row) for row in rows])
    queryset = Role.objects.filter(country=country, active=True).order_by("id")
    with CaptureQueriesContext(connection) as observed:
        ids = [role.id for role in queryset]
        again = [role.id for role in queryset.all()]
    return {"ids": ids, "same": ids == again, "queries": len(observed)}
Reasoning
The counterexample clones the queryset with all before the second iteration. The identities remain correct, but the second object causes another SQL query.

Independent practice: one bounded framework change

Add an optional case-insensitive title substring filter while preserving country, active state and ordering.

Add an optional case-insensitive title substring filter while preserving country, active state and ordering. Start with a term matching one selected role, then an empty term and a term with no matches.

Keep the same queryset object for the repeated iteration. This changes one declared population filter without turning the exercise into a full search engine or adding a database index without measuring its need.

Step 1: Add a title__icontains filter with an empty default. Step 2: Preserve the country and active predicates and the single queryset object.

Practice starter: solve before reading the solution

python

from bootstrap_lab import django_setup
django_setup(__name__)

from bootstrap_lab import install_models
from django.db import models, connection
from django.test.utils import CaptureQueriesContext

class Role(models.Model):
    title = models.CharField(max_length=80)
    country = models.CharField(max_length=2)
    active = models.BooleanField(default=True)
    class Meta:
        app_label = "framework_lab"

install_models(Role)

def selected_ids(rows, country):
    # Remove this placeholder, then adapt the retained baseline:
    # Add a title__icontains filter with an empty default.
    raise NotImplementedError
    Role.objects.all().delete()
    Role.objects.bulk_create([Role(**row) for row in rows])
    queryset = Role.objects.filter(country=country, active=True).order_by("id")
    with CaptureQueriesContext(connection) as observed:
        ids = [role.id for role in queryset]
        again = [role.id for role in queryset]
    return {"ids": ids, "same": ids == again, "queries": len(observed)}
Reasoning
Add a title__icontains filter with an empty default. Preserve the country and active predicates and the single queryset object.
  • Hint 1: Apply the extra lookup before evaluating the queryset.
  • Hint 2: Test a matching inactive role and a matching role in another country.

Solution, tests and trade-offs

The fixture includes roles in another country and an inactive role with otherwise matching text, so a title-only filter cannot pass.

The fixture includes roles in another country and an inactive role with otherwise matching text, so a title-only filter cannot pass. Cases compare actual identities and the measured query count.

The practice keeps an empty selected population distinct from a missing or failed response. The single-query result applies to this controlled queryset evaluation; it is not a claim that every ORM operation or related-object access needs only one query.

Practice solution and acceptance checks

python

from bootstrap_lab import django_setup
django_setup(__name__)

from bootstrap_lab import install_models
from django.db import models, connection
from django.test.utils import CaptureQueriesContext

class Role(models.Model):
    title = models.CharField(max_length=80)
    country = models.CharField(max_length=2)
    active = models.BooleanField(default=True)
    class Meta:
        app_label = "framework_lab"

install_models(Role)

def selected_ids(rows, country, term=""):
    Role.objects.all().delete()
    Role.objects.bulk_create([Role(**row) for row in rows])
    queryset = Role.objects.filter(country=country, active=True, title__icontains=term).order_by("id")
    with CaptureQueriesContext(connection) as observed:
        ids = [role.id for role in queryset]
        again = [role.id for role in queryset]
    return {"ids": ids, "same": ids == again, "queries": len(observed)}
Reasoning
The fixture includes roles in another country and an inactive role with otherwise matching text, so a title-only filter cannot pass. Cases compare actual identities and the measured query count.

Interview reasoning and next step

Explain which expression builds a query and which expression evaluates it.

Explain which expression builds a query and which expression evaluates it. Then distinguish stable ordering, pagination order and snapshot consistency under concurrent changes.

A production search may need indexes, bounded pages and a different transaction isolation policy, but those decisions begin with a precise inclusion rule. The relationship lesson next shows why a correctly filtered queryset can still trigger many extra queries while rendering related objects.

Optional stretch — after the core task works: Inspect a bounded query plan on a larger disposable fixture before proposing an index.

Computer practice: https://applydjinn.com/typorithm/python-frameworks-lab-20261105.zip. Install the pinned dependencies in an isolated environment, run verify.py --track django, then edit the retained exercise baseline and check it with --practice dj-querysets. The lab uses owned in-memory databases, local framework clients and tiny CPU tensors. It never reads the working ApplyDjinn database, contacts production feeds or downloads models.

Select one explicit population, order it deterministically and observe when a queryset actually executes.