from PIL import Image from django.db import models from django.core.validators import MinValueValidator, MaxValueValidator from django.core.exceptions import ValidationError from colorfield.fields import ColorField import logging logger = logging.getLogger("root") def group_based_upload_to(instance, filename): logger.info(instance) return "files/image/{}/{}/{}".format( type(instance).__name__.lower(), instance.id, filename ) def maximum_size_validator(image): max_width = 512 max_height = 512 img = Image.open(image) fw, fh = img.size if fw > max_width or fh > max_height: raise ValidationError("Height or Width is larger than what is allowed") class Environment(models.Model): clear_color = ColorField( blank=True, null=True, verbose_name="Цвет очистки (начальный)" ) clear_color_to = ColorField( blank=True, null=True, verbose_name="Цвет очистки (конечный)" ) hdr_gainmap = models.FileField( upload_to=group_based_upload_to, blank=True, null=True, verbose_name="HDR Gainmap файл" ) hdr_json = models.FileField( upload_to=group_based_upload_to, blank=True, null=True, verbose_name="HDR JSON файл" ) hdr_webp = models.FileField( upload_to=group_based_upload_to, blank=True, null=True, verbose_name="HDR WEBP файл" ) def __str__(self): return f"Среда #{self.id}" class Meta: verbose_name = "Среда" verbose_name_plural = "Среды" class Element3D(models.Model): model_file = models.FileField( upload_to=group_based_upload_to, verbose_name="Файл модели" ) name = models.CharField( max_length=255, verbose_name="Название элемента" ) description = models.TextField( blank=True, null=True, verbose_name="Описание элемента" ) is_enabled = models.BooleanField( default=True, verbose_name="Включен" ) can_not_disable = models.BooleanField( default=False, verbose_name="Невозможно отключить" ) x_pos = models.IntegerField( default=0, verbose_name="Позиция X" ) y_pos = models.IntegerField( default=0, verbose_name="Позиция Y" ) z_pos = models.IntegerField( default=0, verbose_name="Позиция Z" ) def __str__(self): return self.name class Meta: verbose_name = "Элемент 3D" verbose_name_plural = "Элементы 3D" class Scene3D(models.Model): name = models.CharField(max_length=120, verbose_name="Название сцены") description = models.TextField(blank=True, null=True, verbose_name="Описание сцены") elements = models.ManyToManyField("Element3D", verbose_name="Элементы 3D") env = models.ForeignKey( "Environment", on_delete=models.RESTRICT, blank=True, null=True, verbose_name="Среда", ) min_distance = models.IntegerField( default=10, validators=[MinValueValidator(1), MaxValueValidator(600)], verbose_name="Минимальное расстояние", ) max_distance = models.IntegerField( default=20, validators=[MinValueValidator(2), MaxValueValidator(1000)], verbose_name="Максимальное расстояние", ) def __str__(self): return self.name class Meta: verbose_name = "Сцена 3D" verbose_name_plural = "Сцены 3D" class ClickableArea(models.Model): name = models.CharField( "Название", max_length=255, help_text="Название кликабельной области", ) description = models.TextField( "Описание", help_text="Описание кликабельной области", ) target = models.ForeignKey( Scene3D, on_delete=models.PROTECT, related_name="clickable_areas", blank=True, null=True, help_text="На какую сцену ведет клик", ) source = models.ForeignKey( Element3D, on_delete=models.PROTECT, help_text="В каком элементе искать object_name", ) object_name = models.CharField( "Название объекта", max_length=255, help_text="Имя mesh или group в элементе 3D", ) def __str__(self): return self.name