Skip to content

Specs

The specs module provides a layer of syntactic sugar on top of pairs that makes it much quicker and easier to assemble complex trees of producers and projectors. This layer is the real magic of django-readers: a straightforward way of specifying the shape of your data in order to efficiently select and project a complex tree of related objects.

A spec is a list. Under the hood, the specs module is a very lightweight wrapper on top of pairs. Simple transformations are applied to each item in the spec to replace it with the relevant pair function. The list may contain:

  • Strings. These are interpreted as field names and are replaced with pairs.field.
  • Dictionaries serve two purposes:
    • If the dictionary value is a list, they are interpreted as relationships, with the key specifying the relationship name and the value being a "child spec" for projecting the related objects. This is a shortcut for pairs.relationship.
    • If the value is anything else (a string or a (prepare, produce) pair), the value returned by the produce function in the pair is projected under the specified key. This is a shortcut for pairs.producer_to_projector.
  • Projector pairs of (prepare, project) functions. These are left as-is, allowing you to implement your own arbitrarily complex logic if needed.

Import like this: from django_readers import specs

specs.process(spec)

Takes a spec and returns a projector pair (prepare, project).

from django_readers import specs

spec = [
    "name",
    {
        "book_set": [
            "title",
            "publication_date",
        ]
    },
]

prepare, project = specs.process(spec)

queryset = prepare(Author.objects.all())
result = [project(instance) for instance in queryset]

Note

if django-zen-queries is installed (which is recommended!), django-readers will automatically apply queries_disabled() to the prepare and project functions returned by specs.process. See the tutorial for details.

specs.relationship(name, relationship_spec, to_attr=None)

This function implements the behaviour of the {"relationship_name": [child spec..]} functionality in specs.process. It is useful if you wish to pass a to_attr argument to the underlying prefetch:

spec = [
    "name",
    specs.relationship(
        "book_set",
        [
            pairs.filter(publication_date__year__lte=2017),
            "title",
            "publication_date",
        ],
        to_attr="vintage_books",
    ),
]