Files
social-graph/backend/contacts/models.py
T
gitrusprusandCursor b668ee8507 Add network map UX and theme support.
Introduce network map view/components with filtering and positioning, expand contacts/map backend fields and migrations, and add a persistent light/dark theme toggle with graph label color updates for readability.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-28 13:24:48 +03:00

122 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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='Важность (15)',
)
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})'