Skip to content

Instantly share code, notes, and snippets.

@sunmeat
Created March 25, 2026 11:51
Show Gist options
  • Select an option

  • Save sunmeat/d46acdb52eaa18331624cfc5fcd54207 to your computer and use it in GitHub Desktop.

Select an option

Save sunmeat/d46acdb52eaa18331624cfc5fcd54207 to your computer and use it in GitHub Desktop.
налаштування констрейнтів
from django.db import models
from django.db.models import Q, F # для складних запитів, наприклад, для перевірки умов у CheckConstraint
# Q використовується для створення складних умов, F використовується для посилання на інші поля в моделі при створенні обмежень або запитів
# https://docs.djangoproject.com/en/6.0/ref/models/querysets/#django.db.models.Q
# https://docs.djangoproject.com/en/6.0/ref/models/expressions/#django.db.models.F
class Author(models.Model):
name = models.CharField(max_length=100, unique=True)
birth_year = models.IntegerField(null=True, blank=True)
rating = models.DecimalField(max_digits=3, decimal_places=1, default=5.0)
# null=True дозволяє зберігати NULL у базі даних
# blank=True дозволяє залишати поле порожнім у формах Django
class Meta:
db_table = 'authors' # назва таблиці в базі даних. якщо не вказано, Django створить її автоматично у вигляді 'appname_modelname'
ordering = ['name'] # за замовчуванням сортувати авторів за ім'ям в алфавітному порядку
verbose_name = 'Author' # для адміністративної панелі та інших місць, де потрібно відображати назву моделі в однині
verbose_name_plural = 'Authors'
indexes = [
models.Index(fields=['name'], name='idx_author_name'),
# CREATE INDEX - індекс для прискорення пошуку авторів за іменем
]
constraints = [
# CHECK - перевірка, що ім'я автора не порожнє
models.CheckConstraint(
condition=~Q(name=''), # якщо не працює condition=, поставити check=. Q це клас для створення складних умов, ~Q означає "не"
name='author_name_not_empty' # назва обмеження, яка буде використана в базі даних. вона повинна бути унікальною в межах однієї таблиці
),
# CHECK - рік народження має бути реалістичним (між 1000 і поточним роком)
# тут Q з конкретним числом замість func.Now(), бо SQL Server потребує детермінованих виразів у CHECK
models.CheckConstraint(
condition=Q(birth_year__isnull=True) | Q(birth_year__gte=1000, birth_year__lte=2020),
name='author_birth_year_valid'
),
# CHECK - рейтинг автора має бути від 0.0 до 10.0
models.CheckConstraint(
condition=Q(rating__gte=0.0) & Q(rating__lte=10.0),
name='author_rating_range'
),
]
def __str__(self):
return self.name
class Book(models.Model):
title = models.CharField(max_length=200)
author = models.ForeignKey(Author, on_delete=models.CASCADE)
# FOREIGN KEY - при видаленні автора видаляються всі його книги (CASCADE)
pages = models.IntegerField(null=True, blank=True)
price = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True)
discount_price = models.DecimalField(max_digits=8, decimal_places=2, null=True, blank=True)
published_year = models.IntegerField(null=True, blank=True)
stock = models.IntegerField(default=0)
# DEFAULT - stock за замовчуванням дорівнює 0 (немає на складі)
class Meta:
db_table = 'books' # явна назва таблиці
ordering = ['title'] # за замовчуванням сортування за назвою книги
indexes = [
models.Index(fields=['author'], name='idx_book_author'),
# CREATE INDEX - індекс для прискорення пошуку книг за автором (часто використовується у JOIN та WHERE)
models.Index(fields=['title', 'published_year'], name='idx_book_title_year'),
# CREATE INDEX - складений індекс для пошуку книг за назвою та роком видання
]
constraints = [
# UNIQUE - однакові назви книг одного автора заборонені
models.UniqueConstraint(
fields=['title', 'author'],
name='unique_book_per_author'
),
# CHECK - назва книги не може бути порожньою
models.CheckConstraint(
condition=~Q(title=''),
name='book_title_not_empty'
),
# CHECK - кількість сторінок має бути більше 0
models.CheckConstraint(
condition=Q(pages__isnull=True) | Q(pages__gt=0),
name='book_pages_positive'
),
# CHECK - ціна книги має бути невід'ємною
models.CheckConstraint(
condition=Q(price__isnull=True) | Q(price__gte=0),
name='book_price_non_negative'
),
# CHECK - знижкова ціна має бути меншою за звичайну ціну
# F('price') - посилання на інше поле тієї ж моделі
models.CheckConstraint(
condition=Q(discount_price__isnull=True) | Q(price__isnull=True) | Q(discount_price__lt=F('price')),
name='book_discount_less_than_price'
),
# CHECK - кількість на складі не може бути від'ємною
models.CheckConstraint(
condition=Q(stock__gte=0),
name='book_stock_non_negative'
),
# CHECK - рік видання має бути реалістичним
models.CheckConstraint(
condition=Q(published_year__isnull=True) | Q(published_year__gte=1000, published_year__lte=2025),
name='book_published_year_valid'
),
]
def __str__(self):
return self.title
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment