from django.db import models from django.contrib.auth.models import User class Screener(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="screeners") name = models.CharField(max_length=255) filters = models.JSONField(default=dict, blank=True) columns = models.JSONField(default=list, blank=True) selected_symbols = models.JSONField(default=list, blank=True) cached_results = models.JSONField(null=True, blank=True, default=None) last_run_at = models.DateTimeField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["-updated_at"] @staticmethod def _normalize_unique_symbols(values): if not isinstance(values, list): return [] normalized = [] seen = set() for raw in values: symbol = str(raw or "").strip().upper() if not symbol or symbol in seen: continue seen.add(symbol) normalized.append(symbol) return normalized def save(self, *args, **kwargs): # Enforce a canonical selected symbol list on every save path. self.selected_symbols = self._normalize_unique_symbols(self.selected_symbols) super().save(*args, **kwargs) def __str__(self): return f"{self.user.username}: {self.name}" class ScreenerSymbolCache(models.Model): symbol = models.CharField(max_length=32, unique=True) data = models.JSONField(default=dict, blank=True) last_fetched_at = models.DateTimeField() created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ["-last_fetched_at"] def __str__(self): return self.symbol