from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models LIFE_SPHERES = [ ('work', 'Работа'), ('study', 'Учёба'), ('hobby', 'Хобби'), ('family', 'Семья'), ('health', 'Здоровье'), ('other', 'Другое'), ] NETWORK_CIRCLES = [ ('support', 'Круг поддержки'), ('productivity', 'Круг продуктивности'), ('development', 'Круг развития'), ] INTERACTION_INTENSITY = [ ('intense', 'Интенсивные контакты'), ('sparse', 'Редкие контакты'), ] class Contact(models.Model): """Контакт в социальном графе.""" name = models.CharField(max_length=255, verbose_name='Имя') email = models.EmailField(blank=True, verbose_name='Email') phone = models.CharField(max_length=50, blank=True, verbose_name='Телефон') organization = models.CharField(max_length=255, blank=True, verbose_name='Организация') position = models.CharField(max_length=255, blank=True, verbose_name='Должность') notes = models.TextField(blank=True, verbose_name='Заметки') life_sphere = models.CharField( max_length=32, choices=LIFE_SPHERES, default='other', verbose_name='Сфера жизни', ) network_circle = models.CharField( max_length=32, choices=NETWORK_CIRCLES, default='productivity', verbose_name='Круг сети', ) importance = models.PositiveSmallIntegerField( default=3, validators=[MinValueValidator(1), MaxValueValidator(5)], verbose_name='Важность (1–5)', ) include_on_network_map = models.BooleanField( default=False, verbose_name='Показывать на карте сети', ) map_angle = models.FloatField(null=True, blank=True, verbose_name='Угол позиции на карте') map_radius_ratio = models.FloatField( null=True, blank=True, validators=[MinValueValidator(0), MaxValueValidator(1)], verbose_name='Радиус позиции на карте (доля)', ) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['name'] verbose_name = 'Контакт' verbose_name_plural = 'Контакты' def __str__(self): return self.name RELATION_TYPES = [ ('colleague', 'Коллега'), ('friend', 'Друг'), ('family', 'Родственник'), ('acquaintance', 'Знакомый'), ('business', 'Деловой партнёр'), ('other', 'Другое'), ] class Relation(models.Model): """Связь между двумя контактами.""" source = models.ForeignKey( Contact, on_delete=models.CASCADE, related_name='relations_as_source', verbose_name='Источник', ) target = models.ForeignKey( Contact, on_delete=models.CASCADE, related_name='relations_as_target', verbose_name='Цель', ) relation_type = models.CharField( max_length=50, choices=RELATION_TYPES, default='acquaintance', verbose_name='Тип связи', ) description = models.CharField(max_length=255, blank=True, verbose_name='Описание') interaction_intensity = models.CharField( max_length=32, choices=INTERACTION_INTENSITY, default='intense', verbose_name='Интенсивность общения', ) created_at = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('source', 'target') verbose_name = 'Связь' verbose_name_plural = 'Связи' def __str__(self): return f'{self.source} → {self.target} ({self.relation_type})'