/
fakerv
/
PythonProjects
Обзор
Документация
Войти
/
fakerv
/
PythonProjects
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
budget_project/finance/models.py
57 строк
3 KB
vlad
Начало разработки Django API
16 июл 2026, 13:29
16 июл 2026, 13:29
02140ed
Код
Авторство
О чём код?
from django.db import models from django.contrib.auth.models import User from django.core.exceptions import ValidationError from django.utils import timezone class Category(models.Model): """ Категория дохода/расхода. Уникальность: один пользователь не может иметь две одинаковые категории одного типа (доход/расход). """ name = models.CharField(max_length=100, verbose_name="Название") user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="categories", verbose_name="Пользователь") is_income = models.BooleanField(default=False, verbose_name="Доходная категория") class Meta: verbose_name = "Категория" verbose_name_plural = "Категории" unique_together = ["name", "user", "is_income"] def __str__(self) -> str: category_type = "доход" if self.is_income else "расход" return f"{self.name} ({category_type})" class Transaction(models.Model): """ Финансовая операция (доход или расход). """ amount = models.DecimalField(max_digits=12, decimal_places=2, verbose_name="Сумма") category = models.ForeignKey(Category, on_delete=models.PROTECT, related_name="transactions", verbose_name="Категория") date = models.DateField(verbose_name="Дата операции") description = models.TextField(blank=True, verbose_name="Комментарий") user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="transactions", verbose_name="Пользователь") class Meta: verbose_name = "Транзакция" verbose_name_plural = "Транзакции" ordering = ["-date", "-id"] def clean(self) -> None: """ Кросс-полевая валидация: - Расход > 0, доход >= 0 - Дата не в будущем """ # Проверяем, что категория уже выбрана (актуально при создании через ModelForm/админку) if self.category: if not self.category.is_income and self.amount <= 0: raise ValidationError({"amount": "Сумма расхода должна быть больше 0."}) if self.category.is_income and self.amount < 0: raise ValidationError({"amount": "Сумма дохода не может быть отрицательной."}) if self.date and self.date > timezone.now().date(): raise ValidationError({"date": "Дата операции не может быть в будущем."}) def __str__(self) -> str: return f"{self.amount} - {self.category.name} ({self.date})"