Декоратор classproperty
Декоратор classproperty из модуля django.utils.decorators
позволяет определить метод класса как свойство, которое можно
вызывать без создания экземпляра класса. В отличие от обычного
property, который работает с экземплярами, classproperty
работает на уровне класса и принимает первым аргументом ссылку
на класс, а не на экземпляр.
Этот декоратор особенно полезен для создания вычисляемых атрибутов, которые зависят только от структуры класса или данных, общих для всех экземпляров. Например, можно создать свойство, которое возвращает количество записей в модели или строковое представление имени класса.
Синтаксис
from django.utils.decorators import classproperty
class MyClass:
@classproperty
def my_property(cls):
return "value"
Декоратор classproperty применяется к методу класса,
который принимает первым аргументом ссылку на класс (обычно
называется cls) и возвращает вычисляемое значение.
Обращение к такому свойству происходит через имя класса, как
к обычному атрибуту, без вызова метода.
Пример . С моделью Django
Рассмотрим пример создания свойства класса для модели
Article, которое возвращает количество опубликованных статей:
from django.db import models
from django.utils.decorators import classproperty
class Article(models.Model):
title = models.CharField(max_length=100)
status = models.CharField(max_length=20)
@classproperty
def published_count(cls):
return cls.objects.filter(status='published').count()
Теперь свойство можно использовать без создания экземпляра класса:
from myapp.models import Article
count = Article.published_count
print(count)
Результат выполнения кода:
"42"
Пример . Вычисляемое свойство
Создадим класс, который использует classproperty
для динамического формирования имени таблицы:
from django.db import models
from django.utils.decorators import classproperty
class BaseModel(models.Model):
class Meta:
abstract = True
@classproperty
def table_name(cls):
return f"app_{cls.__name__.lower()}"
@classproperty
def verbose_name_plural(cls):
return f"{cls.__name__}s"
Пример использования свойств класса для получения имени таблицы и множественного числа названия:
from myapp.models import BaseModel
class Product(BaseModel):
name = models.CharField(max_length=100)
print(Product.table_name)
print(Product.verbose_name_plural)
Результат выполнения кода:
"app_product"
"Products"
Отличие от cached_property
В отличие от декоратора cached_property, который кеширует
результат для экземпляра, classproperty вычисляет значение
при каждом обращении к свойству класса. Если требуется кеширование
на уровне класса, нужно использовать cached_property
в сочетании с дополнительной логикой или использовать
ручное кеширование.
from django.db import models
from django.utils.decorators import classproperty
class Category(models.Model):
name = models.CharField(max_length=50)
@classproperty
def all_names(cls):
return [c.name for c in cls.objects.all()]
При каждом обращении к Category.all_names будет
выполняться запрос к базе данных. Для кеширования результата
можно использовать ручное кеширование или специальные
декораторы.
Смотрите также
-
декоратор
cached_property,
который кеширует результат свойства для экземпляра -
декоратор
method_decorator,
который применяет декоратор к методам класса -
функция
lazy,
которая создает ленивые вычисления в Django -
функция
mark_safe,
которая помечает строку как безопасную для вывода