Created
March 25, 2026 11:51
-
-
Save sunmeat/d46acdb52eaa18331624cfc5fcd54207 to your computer and use it in GitHub Desktop.
налаштування констрейнтів
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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