Поле GeneratedField
Поле GeneratedField позволяет создавать в модели Django поля, значения которых вычисляются непосредственно на уровне базы данных. Данное поле принимает два обязательных параметра: выражение (expression), определяющее логику вычисления, и параметр output_field, задающий тип данных результата. Значения такого поля обновляются автоматически при изменении данных, от которых оно зависит, и не могут быть изменены вручную через ORM. Поле поддерживается PostgreSQL (начиная с версии 12), MariaDB (10.2+), MySQL (5.7+) и SQLite (3.31+).
Синтаксис
from django.db import models
from django.db.models import F, Value
from django.db.models.functions import Concat
class ModelName(models.Model):
field_name = models.GeneratedField(
expression = Expression,
output_field = models.FieldType(),
db_persist = True / False
)
Пример . Создание модели с GeneratedField
Создадим модель Product с вычисляемым полем полной стоимости с учетом налога:
from django.db import models
from django.db.models import F
from django.db.models.functions import Round
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
tax_rate = models.DecimalField(max_digits=5, decimal_places=2, default=0.13)
price_with_tax = models.GeneratedField(
expression = Round(F('price') * (1 + F('tax_rate')), 2),
output_field = models.DecimalField(max_digits=12, decimal_places=2),
db_persist = True
)
def __str__(self):
return self.name
После создания модели поле price_with_tax будет автоматически вычисляться при добавлении или обновлении записей:
from myapp.models import Product
product = Product.objects.create(
name = 'Laptop',
price = 1000.00,
tax_rate = 0.13
)
print(product.price_with_tax)
Результат выполнения кода:
"1130.00"
Пример . С конкатенацией строк
Используем GeneratedField для создания полного имени пользователя из двух отдельных полей:
from django.db import models
from django.db.models.functions import Concat
from django.db.models import Value
class User(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
full_name = models.GeneratedField(
expression = Concat(F('first_name'), Value(' '), F('last_name')),
output_field = models.CharField(max_length=101),
db_persist = True
)
def __str__(self):
return self.full_name
Теперь при создании пользователя поле full_name заполняется автоматически:
from myapp.models import User
user = User.objects.create(
first_name = 'John',
last_name = 'Doe'
)
print(user.full_name)
Результат выполнения кода:
"John Doe"
Пример . С вычислением возраста
Создадим поле, которое будет вычислять возраст пользователя на основе даты рождения и текущей даты:
from django.db import models
from django.db.models import F, Value
from django.db.models.functions import ExtractYear, Cast, Now
from django.db.models import IntegerField
class Person(models.Model):
name = models.CharField(max_length=100)
birth_date = models.DateField()
age = models.GeneratedField(
expression = ExtractYear(Now()) - ExtractYear(F('birth_date')),
output_field = models.IntegerField(),
db_persist = False
)
def __str__(self):
return self.name
Обратите внимание, что параметр db_persist установлен в False, так как возраст зависит от текущей даты и должен вычисляться при каждом запросе, а не сохраняться в базе данных:
from myapp.models import Person
from datetime import date
person = Person.objects.create(
name = 'Alice',
birth_date = date(1990, 5, 15)
)
print(f"{person.name} is {person.age} years old")
Результат выполнения кода:
"Alice is 36 years old"
Пример . С условным вычислением
Используем условное выражение для вычисления статуса заказа на основе суммы:
from django.db import models
from django.db.models import F, Value, Case, When
from django.db.models.functions import Round
class Order(models.Model):
customer_name = models.CharField(max_length=100)
amount = models.DecimalField(max_digits=10, decimal_places=2)
status = models.GeneratedField(
expression = Case(
When(amount__gte=1000.00, then=Value('Premium')),
When(amount__gte=500.00, then=Value('Standard')),
default=Value('Basic'),
output_field=models.CharField(max_length=20)
),
output_field = models.CharField(max_length=20),
db_persist = True
)
def __str__(self):
return f"{self.customer_name} - {self.status}"
При создании заказов поле status будет автоматически определяться на основе суммы:
from myapp.models import Order
Order.objects.create(customer_name = 'Bob', amount = 1200.00)
Order.objects.create(customer_name = 'Charlie', amount = 750.00)
Order.objects.create(customer_name = 'Dave', amount = 300.00)
for order in Order.objects.all():
print(f"{order.customer_name}: {order.status}")
Результат выполнения кода:
"Bob: Premium"
"Charlie: Standard"
"Dave: Basic"
Смотрите также
-
поле
CharField,
которое используется для хранения строковых данных -
поле
DecimalField,
которое используется для хранения чисел с плавающей точкой -
поле
DateField,
которое используется для хранения дат -
поле
IntegerField,
которое используется для хранения целых чисел