Fields

Django Boogie defines a few fields for your convenience.

EnumField

Django support for enumerations is based on the choices argument of integer or text-based fields. Now that Python 3 supports Enum types, this approach is sub-optimal and also involves lots of undesirable boilerplate.

from django.db import models

class User(models.Model):
    ROLE_TEACHER = 0
    ROLE_STUDENT = 1
    ROLE_CHOICES = [
        (ROLE_TEACHER, 'teacher'),
        (ROLE_STUDENT, 'student'),
    ]
    name = models.CharField(max_length=140)
    role = models.IntegerField(choices=ROLE_CHOICES)

    def can_create_classrooms(self):
        """
        Only teachers can create classrooms.
        """
        return self.role == self.ROLE_TEACHER

Now we can define a RoleEnum and use a EnumField in order to simplify things.

from boogie import models
from boogie.fields import DescriptionEnum


class RoleEnum(DescriptionEnum):
    TEACHER = 0, 'teacher'
    STUDENT = 1, 'student'

class User(models.Model):
    name = models.CharField(max_length=140)
    role = models.EnumField(RoleEnum)

    def can_create_classrooms(self):
        """
        Only teachers can create classrooms.
        """
        return self.role == self.ROLE_TEACHER

The EnumField accepts standard Python Enum and IntEnum classes. Boogie defines the corresponding Enum IntEnum that provides human-friendly names for each enumeration and thus integrates more nicely with Django and gettext.

A model that declares a EnumField is automatically filled with all possible ROLE_* attributes for each value in the enumeration. :class:`EnumField`s automatically computes the ‘choices’ argument, and users cannot override it.

API Documentation

class boogie.fields.EnumField(enum, *args, **kwargs)[source]

A Field type that wraps an enumeration.

It represents each field internally as a string or integer.

Parameters:enum (type) – A subclass of :cls:`enum.Enum`. You should consider using :cls:`boogie.types.DescriptionEnum` in order to provide human-friendly names for each enumeration value.
contribute_to_class(cls, name, *args, **kwargs)[source]

Register the field with the model class it belongs to.

If private_only is True, create a separate instance of this field for every subclass of cls, even if cls is not an abstract model.

deconstruct()[source]

Return enough information to recreate the field as a 4-tuple:

  • The name of the field on the model, if contribute_to_class() has been run.
  • The import path of the field, including the class:e.g. django.db.models.IntegerField This should be the most portable version, so less specific may be better.
  • A list of positional arguments.
  • A dict of keyword arguments.

Note that the positional or keyword arguments must contain values of the following types (including inner values of collection types):

  • None, bool, str, int, float, complex, set, frozenset, list, tuple, dict
  • UUID
  • datetime.datetime (naive), datetime.date
  • top-level classes, top-level functions - will be referenced by their full import path
  • Storage instances - these have their own deconstruct() method

This is because the values here must be serialized into a text format (possibly new Python code, possibly JSON) and these are the only types with encoding handlers defined.

There’s no need to return the exact way the field was instantiated this time, just ensure that the resulting field is the same - prefer keyword arguments over positional ones, and omit parameters with their default values.

formfield(**kwargs)[source]

Return a django.forms.Field instance for this field.

get_db_prep_value(value, connection, prepared=False)[source]

Return field’s value prepared for interacting with the database backend.

Used by the default implementations of get_db_prep_save().

to_python(value)[source]

Convert the input value into the expected Python data type, raising django.core.exceptions.ValidationError if the data can’t be converted. Return the converted value. Subclasses should override this.

class boogie.fields.Enum[source]

Similar to :cls:`boogie.IntEnum`, but accepts any type of value.

class boogie.fields.IntEnum[source]

A subclass of enum.IntEnum that accepts an optional human-friendly description field during declaration.

It is safe to translate description strings.

Usage:
>>> class Roles(IntEnum):
...     TEACHER = 0, 'teacher'
...     STUDENT = 1, 'student'