Skip to main content

django-fdict

Dictionary mappings in the database.

Introduction

In databases, one typically uses JOINs to perform mappings. Imagine for example we have a database of products, then we can add the vat regime, and make a JOIN:

from django.db import models

class VATRate(models.Model):
    name = models.CharField(max_length=32, unique=True)
    pct = models.FloatField()

class Product(models.Model):
    name = models.CharField(max_length=255)
    vat_rate = models.ForeignKey(VATRate, on_delete=models.PROTECT)

and then we can annotate by using a JOIN, like:

Product.objects.annotate(vat_pct=F('vate_rate__pct'))

or we can load the entire VATRate object along each product with .select_related(..):

Product.objects.select_related('vate_rate')

and then fetch it through .vat_rate.


Occasionally, we might want to perform mappings with a Python dictionary. This might be the case when we have no control over the database tables, and the vat rate is missing.

If for example the Product contains a CharField with the vat rate:

class Product(models.Model):
    name = models.CharField(max_length=255)
    country = models.CharField(max_length=2)
    country_of_origin = models.CharField(max_length=2)
    vat_rate = models.CharField(max_length=32)

We might want to perform a dictionary mapping with:

# will *not* work

vat_rates = {'R03': 0.21, 'R02': 0.12, 'R01': 0.06}

Product.annotate(vat_pct=vat_rates[F('vat_rate')])

This is the problem django-fdict wants to solve. We first wrap the entries in an FDict, which is a subclass of dict:

# *hopefully* works

from django_fdict import FDict

vat_rates = FDict({'R03': 0.21, 'R02': 0.12, 'R01': 0.06})

Product.annotate(vat_pct=vat_rates[F('vat_rate')])

this will then set an attribute vat_pct to the

Usually mapping just to get an attribute is not a good idea. It is mainly done for further filtering in the queryset, like:

# *hopefully* works

from django_fdict import FDict

vat_rates = FDict({'R03': 0.21, 'R02': 0.12, 'R01': 0.06})

Product.annotate(vat_pct=vat_rates[F('vat_rate')]).filter(vat_pct__range=(0.10, 0.15))

Multiple fields

One can also apply the trick with two or more fields. Then FDict is given a dictionary where the keys are tuples, for example:

# *hopefully* works

from django_fdict import FDict

vat_rates = FDict({('R03', 'BE'): 0.21, ('R02', 'BE'): 0.12, ('R01', 'BE'): 0.06, ('R03', 'FR'): 0.2, ('R02', 'FR'): 0.1})

Product.annotate(vat_pct=vat_rates[F('vat_rate'), F('country')]).filter(vat_pct__range=(0.10, 0.15))

which normally fetches the VAT rates based on the vat rate label, and the country code.

One can also pass non-F values in the lookups, then it will first filter down the dictionary:

# *hopefully* works

from django_fdict import FDict

vat_rates = FDict({('R03', 'BE'): 0.21, ('R02', 'BE'): 0.12, ('R01', 'BE'): 0.06, ('R03', 'FR'): 0.2, ('R02', 'FR'): 0.1})

Product.annotate(vat_pct=vat_rates[F('vat_rate'), 'BE']).filter(vat_pct__range=(0.10, 0.15))

now we thus always use BE (Belgium) as country in the dictionary lookups.

Query-like keys/values

Strictly speaking the keys, and the values in the dictionary can also be database expressions, for example with the given model:

# *hopefully* works

from django_fdict import FDict

origin = F('country_of_origin')

vat_rates = FDict({('R03', origin): 0.21, ('R02', origin): 0.12, ('R01', origin): 0.06})

Product.annotate(vat_pct=vat_rates[F('vat_rate'), F('country')])

it will produce NULL if the country_of_origin is not the same as the country field. But this makes mapping more complicated and eventually the order in which the entries are mapped might determine the outcome.

Technical details

Databases allow to work with CASE … WHEN … THEN … ELSE … END. The FDict converts the dictionary into a (long) chain of WHEN expressions.

So for the first example we use:

SELECT *
       CASE
           WHEN vat_label = 'R03' THEN 0.21
           WHEN vat_label = 'R02' THEN 0.12
           WHEN vat_label = 'R01' THEN 0.06
           ELSE NULL
        END as vat_pct
FROM product

this can also work for more complicated conditions, like:

SELECT *
       CASE
           WHEN vat_label = 'R03' AND country='BE' THEN 0.21
           WHEN vat_label = 'R02' AND country='BE' THEN 0.12
           WHEN vat_label = 'R01' AND country='BE' THEN 0.06
           WHEN vat_label = 'R03' AND country='FR' THEN 0.20
           WHEN vat_label = 'R02' AND country='FR' THEN 0.10
           ELSE NULL
        END as vat_pct
FROM product

Metadata

Release files for django-fdict 0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for django-fdict 0.1
File Interpreter ABI Platform
django_fdict-0.1-py3-none-any.whl Python 3 none any Details

Release files / django_fdict-0.1-py3-none-any.whl

Download URL django_fdict-0.1-py3-none-any.whl
Size 4.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
83d43a28ca02212ad7fd50203980764af30e2899ce88212d74318434de986334
BLAKE2b-256 checksum
How to use checksums
dc0115b473ccbc0951447ba12ed7dc363906a64398a0ae2d20bffbb911137549
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 4, 2026.

Transparency log

Security for django-fdict 0.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 1 file in this release has been uploaded with provenance metadata.

Attestation for django_fdict-0.1-py3-none-any.whl

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1 This release

1 release file Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page