4.9. Models Field Special

  • models.UUIDField - a field for storing UUID values (universally unique identifiers)

  • models.CommaSeparatedIntegerField - a CharField that checks that the value is a comma-separated list of integers

  • models.GenericIPAddressField - a CharField that checks that the value is a valid IPv4 or IPv6 address

  • models.IPAddressField - deprecated in favor of GenericIPAddressField

  • models.JSONField - stores a field for storing JSON-encoded data. In Python, it is a dict

  • models.GeneratedField - a field that is automatically populated with a value when the model is saved

4.9.1. SetUp

>>> from django.db import models
>>> from django.utils.translation import gettext_lazy as _

4.9.2. Arguments

  • blank

  • choices

  • db_column

  • db_index

  • default

  • editable

  • error_message

  • help_text

  • limit_choices_to

  • max_length

  • null

  • primary_key

  • unique

  • validators

  • verbose_name

4.9.3. UUIDField

  • UUIDField

  • from uuid import uuid4

>>> from uuid import uuid4
>>>
>>> identifier = models.UUIDField(
...     verbose_name=_('UUID'),
...     unique=True,
...     null=False,
...     blank=False,
...     editable=False,
...     default=uuid4,
... )

4.9.4. CommaSeparatedIntegerField

  • CommaSeparatedIntegerField

4.9.5. GenericIPAddressField

  • GenericIPAddressField

>>> ip_address = models.GenericIPAddressField(
...     verbose_name=_('IP Address'),
...     null=True,
...     blank=True,
...     default=None
... )

4.9.6. IPAddressField

  • IPAddressField

4.9.7. JSONField

  • JSONField

4.9.8. GeneratedField

A field that is always computed based on other fields in the model. This field is managed and updated by the database itself. Uses the GENERATED ALWAYS SQL syntax.

There are two kinds of generated columns: stored and virtual. A stored generated column is computed when it is written (inserted or updated) and occupies storage as if it were a regular column. A virtual generated column occupies no storage and is computed when it is read. Thus, a virtual generated column is similar to a view and a stored generated column is similar to a materialized view.

The expressions should be deterministic and only reference fields within the model (in the same database table). Generated fields cannot reference other generated fields. Database backends can impose further restrictions.

PostgreSQL only supports persisted columns. Oracle only supports virtual columns.

Since the database always computed the value, the object must be reloaded to access the new value after save(), for example, by using refresh_from_db().

>>> 
... from django.db import models
... from django.db.models import F
...
...
... class Square(models.Model):
...     side = models.IntegerField()
...     area = models.GeneratedField(
...         expression=F("side") * F("side"),
...         output_field=models.BigIntegerField(),
...         db_persist=True,
...     )

4.9.9. Use Case - 1

>>> 
... from uuid import uuid4
... from django.db import models
... from django.utils.translation import gettext_lazy as _
...
...
... class Customer(models.Model):
...     uuid = models.UUIDField(verbose_name=_('Unique UUID'), unique=True, null=False, blank=False, default=uuid4, editable=False)
...     ip_address = models.GenericIPAddressField(verbose_name=_('IP Address'), null=True, blank=True, default=None, editable=False)
...     payload = models.JSONField(verbose_name=_('Payload'), null=True, blank=True, default=None)
...
...     def __str__(self):
...         return f'{self.firstname} {self.lastname}'
...
...     class Meta:
...         verbose_name = _('Customer')
...         verbose_name_plural = _('Customers')

4.9.10. Assignments

# TODO: Create Tests
# doctest: +SKIP_FILE
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% About
# - Name: Django Model Special
# - Difficulty: easy
# - Lines: 1
# - Minutes: 3

# %% English
# 0. Use `myproject.demo`
# 1. Alter model `Person`
# 2. Add field `identifier` as `models.UUIDField`:
#    - verbose_name=_('Identifier')
#    - editable=False
#    - unique=True
#    - null=False
#    - blank=False
#    - default=uuid4
# 3. Use `gettext_lazy`
# 4. Run `makemigrations`
# 5. Run `migrate`

# %% Polish
# 0. Użyj `myproject.demo`
# 1. Zmień model `Person`
# 2. Dodaj pole `identifier` jako `models.UUIDField`:
#    - verbose_name=_('Identifier')
#    - editable=False
#    - unique=True
#    - null=False
#    - blank=False
#    - default=uuid4
# 3. Użyj `gettext_lazy`
# 4. Uruchom `makemigrations`
# 5. Uruchom `migrate`

# %% Hints
# - `uuid.uuid4()`

# %% Output
# - `Add field identifier to person`
# - `Applying demo.0007_person_identifier... OK`

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 10), \
'Python 3.10+ required'
"""

from uuid import uuid4
from django.db import models
from django.utils.translation import gettext_lazy as _


class Person(models.Model):
    identifier = ...

# TODO: Create Tests
# doctest: +SKIP_FILE
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% About
# - Name: Django Model Special
# - Difficulty: easy
# - Lines: 1
# - Minutes: 3

# %% English
# 0. Use `myproject.demo`
# 1. Alter model `Person`
# 2. Add field `ip_address` as `models.GenericIPAddressField`:
#    - verbose_name=_('IP Address')
#    - null=True
#    - blank=True
#    - default=None
# 3. Use `gettext_lazy`
# 4. Run `makemigrations`
# 5. Run `migrate`

# %% Polish
# 0. Użyj `myproject.demo`
# 1. Zmień model `Person`
# 2. Dodaj pole `ip_address` jako `models.GenericIPAddressField`:
#    - verbose_name=_('IP Address')
#    - null=True
#    - blank=True
#    - default=None
# 3. Użyj `gettext_lazy`
# 4. Uruchom `makemigrations`
# 5. Uruchom `migrate`

# %% Output
# - `Add field ip_address to person`
# - `Applying demo.0007_person_ip_address... OK`

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 10), \
'Python 3.10+ required'
"""

from django.db import models
from django.utils.translation import gettext_lazy as _


class Person(models.Model):
    ip_address = ...

# TODO: Create Tests
# doctest: +SKIP_FILE
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author

# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`

# %% About
# - Name: Django Model Special
# - Difficulty: easy
# - Lines: 1
# - Minutes: 3

# %% English
# 0. Use `myproject.demo`
# 1. Alter model `Person`
# 2. Add field `data` as `models.JSONField`:
#    - verbose_name=_('Data')
#    - null=True
#    - blank=True
#    - default=None
# 3. Use `gettext_lazy`
# 4. Run `makemigrations`
# 5. Run `migrate`

# %% Polish
# 0. Użyj `myproject.demo`
# 1. Zmień model `Person`
# 2. Dodaj pole `data` jako `models.JSONField`:
#    - verbose_name=_('Data')
#    - null=True
#    - blank=True
#    - default=None
# 3. Użyj `gettext_lazy`
# 4. Uruchom `makemigrations`
# 5. Uruchom `migrate`

# %% Output
# - `Add field data to person`
# - `Applying demo.0007_person_data... OK`

# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 10), \
'Python 3.10+ required'
"""

from django.db import models
from django.utils.translation import gettext_lazy as _


class Person(models.Model):
    data = ...