Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/flaeppe/django-choicefield

An enum field for Django models
https://github.com/flaeppe/django-choicefield

django enum enumfield python

Last synced: 20 days ago
JSON representation

An enum field for Django models

Awesome Lists containing this project

README

        

Django ChoiceField


Test workflow Status

PyPI Package
Python versions

A Django model field that casts enum values to its enum type. Supports all enum types
shipped with Django and Python 3 native enum types.

---

### Motivation

Have you also felt annoyed by having to convert
[Django's enumeration types](https://docs.djangoproject.com/en/dev/ref/models/fields/#enumeration-types)
_back_ to its type? Using tricks seen below to cast it.

```python
class Suit(models.IntegerChoices):
DIAMOND = 1
SPADE = 2
HEART = 3
CLUB = 4

class Card(models.Model):
suit_kind = models.IntegerField(choices=Suit.choices, db_column="suit")

@property
def suit(self) -> Suit:
return Suit(self.suit_kind)
```

This is what `django-choicefield` helps out with. While it additionally supports using
Python's native [enum.Enum](https://docs.python.org/3/library/enum.html) to express
column values.

### Features

#### Using Django's enumeration types

```python
import choicefield
from django.db import models

class Suit(models.IntegerChoices):
DIAMOND = 1
SPADE = 2
HEART = 3
CLUB = 4

class Card(models.Model):
suit = choicefield.ChoiceField(Suit)

instance = Card.objects.create(suit=Suit.CLUB)
assert instance.suit is Suit.CLUB
```

There's also support for Django's `models.TextChoices`.

#### Using Python's native enumeration

```python
import choicefield
from enum import Enum
from django.db import models

class Suit(int, Enum):
DIAMOND = 1
SPADE = 2
HEART = 3
CLUB = 4

class Card(models.Model):
suit = choicefield.ChoiceField(Suit)

instance = Card.objects.create(suit=Suit.DIAMOND)
assert instance.suit is Suit.DIAMOND
```

#### Passing enum values

It's also possible to pass the _value_ of an enum, which will be converted to its
corresponding enum instance.

```python
instance = Card(suit=2)
assert instance.suit is Suit.SPADE
instance.save()
assert instance.suit is Suit.SPADE
instance = Card.objects.get(suit=2)
assert instance.suit is Suit.SPADE
```

### Getting stored database values

If you want to access the stored database values, without conversion to your enum type,
you can use the registered `__raw` transformer.

```python
Card.objects.values("suit__raw")
#
```

#### Getting unrecognized values from database

In case of e.g. a migration where an enum has changed by, say, removing a value. The
database could have values not recognized by the registered enum. Thus it could be
necessary to retrieve values _without_ casting them to an enum instance, as it'd raise
an error.

It can be done using the `__raw` transformer while also sidestepping enum validation in
filter values by using
[`Value` expressions](https://docs.djangoproject.com/en/dev/ref/models/expressions/#value-expressions)

```python
Card.objects.filter(suit=Value(1337)).values_list("suit__raw", flat=True)
#
```

### Installation

Using `pip`

```console
$ pip install django-choicefield
```

### Development

#### Running tests

Running the whole test matrix

```console
$ tox
```

Setting up a development environment

```console
$ tox -e dev
```

Running the test suite for one environment (non editable)

e.g. `Django==4.0.x` and `Python3.11`

```console
$ tox -e django40-py311
```

#### Start a local example project

There are a couple of shortcut commands available using
[Taskfile](https://taskfile.dev/), for your convenience.

e.g.

```console
$ task manage -- createsuperuser
$ task runserver
```

After [installing Taskfile](https://taskfile.dev/installation/) you can run
`task --list-all` to find all available commands.

### Compatibility

`django-choicefield` is tested according to the table below

| Django version | Python version |
| -------------- | -------------- |
| 5.0.x | ^3.10 |
| 4.2.x | ^3.9 |
| 4.1.x | ^3.9 |
| 4.0.x | ^3.9 |
| 3.2.x | ^3.9 |