Skip to main content

git@github.com:tolomea/django-auto-prefetch.git

Project description

django-auto-prefetch

Automatically prefetch foreign key values as neededa

Purpose

When accessing a foreign key on a model instance, if the field's value has not yet been loaded then auto-prefetch will prefetch the field for all model instances loaded by the same queryset as the current model instance. This is enabled at the model level and totally automatic and transparent for users of the model.

Usage

Everywhere you use Model, QuerySet, Manager or ForeignKey from django.db.models instead use them from auto_prefetch. No other changes are required.

Background & Rationale

Currently when accessing an uncached foreign key field, Django will automatically fetch the missing value from the Database. When this occurs in a loop it creates 1+N query problems. Consider the following snippet:

for choice in Choice.objects.all():
    print(choice.question.question_text, ':', choice.choice_text)

This will do one query for the choices and then one query per choice to get that choice's question. This behavior can be avoided with correct application of prefetch_related like this:

for choice in Choice.objects.prefetch_related('question'):
    print(choice.question.question_text, ':', choice.choice_text)

This has several usability issues, notably:

  • Less experienced users are generally not aware that it's necessary.
  • Cosmetic seeming changes to things like templates can change the fields that should be prefetched.
  • Related to that the code that requires the prefetch_related (template for example) may be quite removed from where the prefetch_related needs to be applied (view for example).
  • Subsequently finding where prefetch_related calls are missing is non trivial and needs to be done on an ongoing basis.
  • Excess fields in prefetch_related calls are even harder to find and result in unnecessary database queries.
  • It is very difficult for libraries like the admin and Django Rest Framework to automatically generate correct prefetch_related clauses.

On the first iteration of the loop in the example above, when we first access a choice's question field, instead of fetching the question for just that choice, auto-prefetch will speculatively fetch the questions for all the choices returned by the queryset. This change results in the first snippet having the same database behavior as the second while reducing or eliminating all of the noted usability issues.

Some important points:

  • Many2Many and One2One fields are not changed at all.
  • Because these are foreign key fields the generated queries can't have more result rows than the original query and may have less. This eliminates any concern about a multiplicative query size explosion.
  • This feature will never result in more database queries as a prefetch will only be issued where the ORM was already going to fetch a related object.
  • Because it is triggered by fetching missing related objects it will not at all change the DB behavior of code which is full covered by prefetch_related (and select_related) calls.
  • This will inherently chain across relations like choice.question.author, the conditions above still hold under such chaining.
  • It may result in larger data transfer between the database and Django in some situations. An example of that last point is:
qs = Choice.objects.all()
list(qs)[0].question

Such examples generally seem to be rarer and more likely to be visible during code inspection (vs {{choice.question}} in a template). And larger queries are usually a better failure mode than producing hundreds of queries. For this to actually produce inferior behavior in practice you need to:

fetch a large number of choices

filter out basically all of them

in a way that prevents garbage collection of the unfiltered ones

If any of those aren't true then automatic prefetching will still produce equivalent or better database behavior than without.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-auto-prefetch-0.0.1.tar.gz (5.1 kB view details)

Uploaded Source

Built Distribution

django_auto_prefetch-0.0.1-py3-none-any.whl (6.6 kB view details)

Uploaded Python 3

File details

Details for the file django-auto-prefetch-0.0.1.tar.gz.

File metadata

  • Download URL: django-auto-prefetch-0.0.1.tar.gz
  • Upload date:
  • Size: 5.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/46.1.1 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.8.0

File hashes

Hashes for django-auto-prefetch-0.0.1.tar.gz
Algorithm Hash digest
SHA256 133c0fac88e1272a8ca83b92029ae13c68941680f0f20fe023fd377ae71d8770
MD5 ce2910a20d55829397ab1f6117ef8baf
BLAKE2b-256 e1168daa5de893070aeaadb2035ea8f288ac9c55835687dcda0bce5bd1f1c1f6

See more details on using hashes here.

File details

Details for the file django_auto_prefetch-0.0.1-py3-none-any.whl.

File metadata

  • Download URL: django_auto_prefetch-0.0.1-py3-none-any.whl
  • Upload date:
  • Size: 6.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.23.0 setuptools/46.1.1 requests-toolbelt/0.9.1 tqdm/4.43.0 CPython/3.8.0

File hashes

Hashes for django_auto_prefetch-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 07600651cd7bd22a04df44b82ad874f9e9343310a38c1c332dc5b53182124ad9
MD5 ad27845cab8be1a520db71e9cc852a3d
BLAKE2b-256 93e54ee6d0e532b3bdeca5cadbe9a2dbe1fe09785b1b3c9320e42f1866cdb906

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page