Skip to content

Fields

Even if we tried to keep most of the native Django fields, we had to override some of them to be more fit for RESTful applications. Also, we introduced new ones, to cover extra functionality like nested requests. In this section, we will explain our intentions and describe their usage.

To sum up:

Fields that are not in the list above were not been tested or been replaced with our customized implementation (or it just doesn't make sense to use them in RESTful APIs).

BooleanField

  • Normalizes to: A Python True or False value (or None if it's not required)

Django BooleanField checks only for False (false, 0) values and everything else is suppose to be True.

In my point of view this kind of behaviour it's little bit weird, so we decided to check explicitly for True and False values. If field is required ValidationError is raised or value is normalized as None.

Checked values:

  • True: True 'True' 'true' 1 '1'
  • False: False 'False' 'false' 0 '0'

Note: We would like to change this behaviour to support only boolean values and rely on deserializers.

FieldList

This field is used to parse list of primitive values (like strings or numbers). If you want to parse list of object, check FormFieldList.

  • Normalizes to: A Python list
  • Error message keys: not_field, not_list, min_length, max_length
  • Required arguments:
  • field: Instance of a form field representing children
  • Optional arguments:
  • min_length: Minimum length of field size as integer
  • max_length: Maximum length of field size as integer

JSON example

{
    "numbers": [
        0,
        1,
        1,
        2,
        3,
        5,
        8,
        13
    ]
}

Python representation

from django_api_forms import Form, FieldList
from django.forms import fields


class FibonacciForm(Form):
    numbers = FieldList(field=fields.IntegerField())

FormField

Field used for embedded objects represented as another API form.

  • Normalizes to: A Python dictionary
  • Required arguments:
  • form: Type of a nested form

JSON example

{
    "title": "Unknown Pleasures",
    "year": 1979,
    "artist": {
        "name": "Joy Division",
        "genres": [
            "rock",
            "punk"
        ],
        "members": 4
    }
}

Python representation

from django_api_forms import Form, FormField, FieldList
from django.forms import fields


class ArtistForm(Form):
    name = fields.CharField(required=True, max_length=100)
    genres = FieldList(field=fields.CharField(max_length=30))
    members = fields.IntegerField()


class AlbumForm(Form):
    title = fields.CharField(max_length=100)
    year = fields.IntegerField()
    artist = FormField(form=ArtistForm)

FormFieldList

Field used for embedded objects represented as another API form.

  • Normalizes to: A Python list of dictionaries
  • Error message keys: not_list, min_length, max_length
  • Required arguments:
  • form: Type of a nested form
  • Optional arguments:
  • min_length: Minimum length of field size as integer
  • max_length: Maximum length of field size as integer

JSON example

{
    "title": "Rock For People",
    "artists": [
        {
            "name": "Joy Division",
            "genres": [
                "rock",
                "punk"
            ],
            "members": 4
        }
    ]
}

Python representation

from django_api_forms import Form, FormFieldList, FieldList
from django.forms import fields


class ArtistForm(Form):
    name = fields.CharField(required=True, max_length=100)
    genres = FieldList(field=fields.CharField(max_length=30))
    members = fields.IntegerField()


class FestivalForm(Form):
    title = fields.CharField(max_length=100)
    year = fields.IntegerField()
    artists = FormFieldList(form=ArtistForm)

EnumField

Tip: Django has pretty cool implementation of the enumeration types.

  • Normalizes to: A Python Enum object
  • Error message keys: not_enum, invalid
  • Required arguments:
  • enum: Enum class

JSON example

{
    "title": "Rock For People",
    "type": "vinyl"
}

Python representation

from django_api_forms import Form, EnumField
from django.forms import fields
from django.db.models import TextChoices


class AlbumType(TextChoices):
    CD = 'cd', 'CD'
    VINYL = 'vinyl', 'Vinyl'


class AlbumForm(Form):
    title = fields.CharField(required=True, max_length=100)
    type = EnumField(enum=AlbumType)

DictionaryField

Field created for containing typed value pairs. Due to inverted key, value parameters in __init__ method, value_field is forced keyword arguments.

  • Normalizes to: A Python dictionary
  • Error message keys: not_dict, not_field
  • Required arguments:
  • value_field: Type of a nested form
  • Optional arguments:
  • key_field: Type of a nested form

JSON example

{
    "my_dict": {
        "b061bb03-1eaa-47d0-948f-3ce1f15bf3bb": 2.718,
        "0a8912f0-6c10-4505-bc27-bbb099d2e395": 42
    }
}

Python representation

from django_api_forms import Form, DictionaryField
from django.forms import fields


class DictionaryForm(Form):
    my_typed_dict = DictionaryField(value_field=fields.DecimalField(), key_field=fields.UUIDField())

AnyField

Field without default validators.

JSON example

{
    "singer": {
        "name": "Johnny",
        "surname": "Rotten",
        "age": 64,
        "born_at": "1956-01-31"
    }
}

Python representation

from django_api_forms import Form, DictionaryField, AnyField


class BandForm(Form):
    singer = DictionaryField(value_field=AnyField())

FileField

This field contains BASE64 encoded file.

  • Normalizes to: A Django File object
  • Error message keys: max_length, invalid_uri, invalid_mime
  • Arguments:
  • max_length: Maximum files size in bytes (optional)
  • mime: Tuple of allowed mime types (optional - if present, value must be in form of Data URI)
  • Extra normalised attributes:
  • file_field.clean(payload).content_type: Mime type (str - e.g. audio/mpeg) of containing file (None if unable to detect - if payload is not in DATA URI format)

JSON example

{
    "title": "Disorder",
    "type": "data:audio/mpeg;base64,SGVsbG8sIFdvcmxkIQ=="
}

Python representation

from django_api_forms import Form, FileField
from django.conf import settings
from django.forms import fields


class SongForm(Form):
    title = fields.CharField(required=True, max_length=100)
    audio = FileField(max_length=settings.DATA_UPLOAD_MAX_MEMORY_SIZE, mime=('audio/mpeg',))

ImageField

This field contains BASE64 encoded image. Depends on Pillow because normalized value contains Image object. Pillow is also used for image validation Image.verify() is called.

  • Normalizes to: A Django File object
  • Error message keys: max_length, invalid_uri, invalid_mime, invalid_image (if Image.verify() failed)
  • Arguments:
  • max_length: Maximum files size in bytes (optional)
  • mime: Tuple of allowed mime types (optional, value must be in Data URI)
  • Extra normalised attributes:
  • image_field.clean(payload).content_type: Mime type (str - e.g. audio/mpeg) of containing file (None if unable to detect - if payload is not in DATA URI format). Value is filled using Pillow Image.MIME.get(image.format))
  • image_field.clean(payload).image: A Pillow Image object instance

JSON example

{
    "title": "Unknown pleasures",
    "cover": "data:image/png;base64,SGVsbG8sIFdvcmxkIQ=="
}

Python representation

from django_api_forms import Form, ImageField
from django.conf import settings
from django.forms import fields


class AlbumForm(Form):
    title = fields.CharField(required=True, max_length=100)
    cover = ImageField(max_length=settings.DATA_UPLOAD_MAX_MEMORY_SIZE, mime=('image/png',))

RRule Field

This field contains RRule object.

  • Normalizes to a Dateutil RRule object.
  • Error message keys: not_rrule

Python representation

from django_api_forms import Form, RRuleField


class VacationForm(Form):
    rrule = RRuleField(required=True)

GeoJSON Field

This field contains GEOSGeometry django GEOS object. Translates GeoJSON format into geodjango fields. Depends on gdal because of spatial reference system (SRS) which is specified in this library.

  • Error message keys: not_dict, not_geojson, not_int, transform_error
  • Arguments:
  • srid: spatial reference identifier (optional - default 4326)
  • transform: transform to different spatial reference identifier (optional)

GeoJSON example

{
    "geometry": {
         "type": "Point",
         "coordinates": [90.0, 40.0]
     }
}

Python representation

from django_api_forms import Form, GeoJSONField


class VacationForm(Form):
    geometry = GeoJSONField(required=True, srid=4326, transform=5514)