5.11. Models Method Property — Python
@propertyis a Python decorator that allows you to define a method that behaves like an attributeThis fields are not stored in the database
They are calculated when accessed
They are read-only (can't be set)
They can be used in the Django Admin
>>> # ... from datetime import date ... from django.db import models ... from django.utils.translation import gettext_lazy as _ ... from shop.models import Address, Email ... ... ... class Customer(models.Model): ... firstname = models.CharField(verbose_name=_('First Name'), max_length=100, null=False, blank=False) ... lastname = models.CharField(verbose_name=_('Last Name'), max_length=100, null=False, blank=False, db_index=True) ... ... @property ... def age(self, year=365.25): ... days = (date.today() - self.birthdate).days ... return int(days / year) ... ... @property ... def emails(self): ... return Email.objects.filter(customer=self) ... ... @property ... def addresses(self): ... return Address.objects.filter(customer=self) ... ... @property ... def changelog(self): ... from django.contrib.contenttypes.models import ContentType ... from django.contrib.admin.models import LogEntry ... model = self.__class__.__name__.lower() ... app_label = self.__class__._meta.app_label ... ct = ContentType.objects.get(app_label=app_label, model=model) ... return LogEntry.objects.filter(content_type=ct, object_id=self.pk)
... def __str__(self): ... return f'{self.firstname} {self.lastname}' ... ... class Meta: ... verbose_name = _('Customer') ... verbose_name_plural = _('Customers')
5.11.1. Assignments
# TODO: Create Tests # doctest: +SKIP_FILE # %% About # - Name: Django Model Property # - Difficulty: easy # - Lines: 4 # - Minutes: 5 # %% 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 # %% English # 0. Use `myproject.myapp` # 1. Modify model `Person` # 2. Add property fullname that returns `f'{self.first_name} {self.last_name}'` # 3. Use `@property` decorator # 4. Run `makemigrations` # 5. Run `migrate` # %% Polish # 0. Użyj `myproject.myapp` # 1. Stwórz model `Person` # 2. Dodaj właściwość fullname, która zwraca `f'{self.first_name} {self.last_name}'` # 3. Użyj dekoratora `@property` # 4. Uruchom `makemigrations` # 5. Uruchom `migrate` # %% Expected # %% Doctests """ >>> import sys; sys.tracebacklimit = 0 >>> assert sys.version_info >= (3, 12), \ 'Python has an is invalid version; expected: `3.12` or newer.' """ # %% Run # - PyCharm: right-click in the editor and `Run Doctest in ...` # - PyCharm: keyboard shortcut `Control + Shift + F10` # - Terminal: `python -m doctest -f -v myfile.py` # %% Imports from django.db import models from django.utils.translation import gettext_lazy as _ # %% Types Group: type[models.Model] # %% Data # %% Result class Person(models.Model): firstname = models.CharField(verbose_name=_('Firstname'), max_length=30, default=None, null=True, blank=True) lastname = models.CharField(verbose_name=_('Lastname'), max_length=30, null=False, blank=False, db_index=True)
# TODO: Create Tests # doctest: +SKIP_FILE # %% About # - Name: Django Model Property # - Difficulty: easy # - Lines: 4 # - Minutes: 5 # %% 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 # %% English # 0. Use `myproject.myapp` # 1. Modify model `Person` # 2. Add property `age` that returns age in years based on `self.birthdate` # 3. Mind, that field `birthdate` can be `NULL`, then return `None` # 4. Use `@property` decorator # 5. Run `makemigrations` # 6. Run `migrate` # %% Polish # 0. Użyj `myproject.myapp` # 1. Stwórz model `Person` # 2. Dodaj property `age`, która zwraca wiek w latach na podstawie `self.birthdate` # 3. Pamiętaj, że pole `birthdate` może być `NULL`, wtedy zwróć `None` # 4. Użyj dekoratora `@property` # 5. Uruchom `makemigrations` # 6. Uruchom `migrate` # %% Expected # %% Doctests """ >>> import sys; sys.tracebacklimit = 0 >>> assert sys.version_info >= (3, 12), \ 'Python has an is invalid version; expected: `3.12` or newer.' """ # %% Run # - PyCharm: right-click in the editor and `Run Doctest in ...` # - PyCharm: keyboard shortcut `Control + Shift + F10` # - Terminal: `python -m doctest -f -v myfile.py` # %% Imports from django.db import models from django.utils.translation import gettext_lazy as _ # %% Types Group: type[models.Model] # %% Data # %% Result class Person(models.Model): birthdate = models.DateField(verbose_name=_('Birthdate'), null=True, blank=True, default=None)