Initial commit: Diario Conversazioni Olimpic Nastri
- Django 5.2 + PostgreSQL + Gunicorn - Conversazioni, Obiettivi, Documenti PDF, Persone - Commenti e aggiornamenti con modifica/eliminazione - Agenda, ricerca live, giorni rimanenti scadenze - Bootstrap 5 + HTMX + toast notifications - Deploy: Nginx + Gunicorn + SSL
This commit is contained in:
139
diario/models.py
Normal file
139
diario/models.py
Normal file
@@ -0,0 +1,139 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.validators import FileExtensionValidator
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
def validate_file_size(value):
|
||||
limit = 10 * 1024 * 1024 # 10 MB
|
||||
if value.size > limit:
|
||||
from django.core.exceptions import ValidationError
|
||||
raise ValidationError('Il file non può superare i 10 MB.')
|
||||
|
||||
|
||||
class Conversazione(models.Model):
|
||||
titolo = models.CharField(max_length=200)
|
||||
data = models.DateTimeField()
|
||||
partecipanti = models.ManyToManyField(User, related_name='conversazioni_partecipate', blank=True)
|
||||
contenuto = models.TextField()
|
||||
registrato_da = models.ForeignKey(
|
||||
User, on_delete=models.SET_NULL, null=True, related_name='conversazioni_registrate'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-data']
|
||||
verbose_name = 'Conversazione'
|
||||
verbose_name_plural = 'Conversazioni'
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.titolo} ({self.data.strftime('%d/%m/%Y')})"
|
||||
|
||||
|
||||
class Obiettivo(models.Model):
|
||||
TIPO_CHOICES = [
|
||||
('collettivo', 'Collettivo'),
|
||||
('individuale', 'Individuale'),
|
||||
]
|
||||
STATO_CHOICES = [
|
||||
('aperto', 'Aperto'),
|
||||
('in_corso', 'In corso'),
|
||||
('completato', 'Completato'),
|
||||
('sospeso', 'Sospeso'),
|
||||
]
|
||||
|
||||
titolo = models.CharField(max_length=200)
|
||||
descrizione = models.TextField(blank=True)
|
||||
avanzamento = models.PositiveSmallIntegerField(default=0) # 0-100
|
||||
tipo = models.CharField(max_length=20, choices=TIPO_CHOICES, default='collettivo')
|
||||
assegnato_a = models.ManyToManyField(
|
||||
User, blank=True,
|
||||
related_name='obiettivi_assegnati'
|
||||
)
|
||||
stato = models.CharField(max_length=20, choices=STATO_CHOICES, default='aperto')
|
||||
data_scadenza = models.DateField(null=True, blank=True)
|
||||
creato_da = models.ForeignKey(
|
||||
User, on_delete=models.SET_NULL, null=True, related_name='obiettivi_creati'
|
||||
)
|
||||
data_creazione = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-data_creazione']
|
||||
verbose_name = 'Obiettivo'
|
||||
verbose_name_plural = 'Obiettivi'
|
||||
|
||||
def __str__(self):
|
||||
return self.titolo
|
||||
|
||||
@property
|
||||
def giorni_rimanenti(self):
|
||||
"""Restituisce i giorni rimanenti alla scadenza (None se non impostata)."""
|
||||
if not self.data_scadenza:
|
||||
return None
|
||||
delta = self.data_scadenza - timezone.now().date()
|
||||
return delta.days
|
||||
|
||||
|
||||
class AggiornamentoObiettivo(models.Model):
|
||||
obiettivo = models.ForeignKey(Obiettivo, on_delete=models.CASCADE, related_name='aggiornamenti')
|
||||
testo = models.TextField()
|
||||
autore = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='aggiornamenti')
|
||||
data = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-data']
|
||||
verbose_name = 'Aggiornamento'
|
||||
verbose_name_plural = 'Aggiornamenti'
|
||||
|
||||
def __str__(self):
|
||||
return f"Aggiornamento su '{self.obiettivo}' del {self.data.strftime('%d/%m/%Y')}"
|
||||
|
||||
|
||||
class CommentoConversazione(models.Model):
|
||||
conversazione = models.ForeignKey(Conversazione, on_delete=models.CASCADE, related_name='commenti')
|
||||
testo = models.TextField()
|
||||
autore = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='commenti_conversazione')
|
||||
data = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-data']
|
||||
verbose_name = 'Commento'
|
||||
verbose_name_plural = 'Commenti'
|
||||
|
||||
def __str__(self):
|
||||
return f"Commento su '{self.conversazione}' del {self.data.strftime('%d/%m/%Y')}"
|
||||
|
||||
|
||||
class Documento(models.Model):
|
||||
file = models.FileField(
|
||||
upload_to='documenti/%Y/%m/',
|
||||
validators=[
|
||||
FileExtensionValidator(allowed_extensions=['pdf']),
|
||||
validate_file_size,
|
||||
],
|
||||
)
|
||||
titolo = models.CharField(max_length=200)
|
||||
descrizione = models.TextField(blank=True)
|
||||
caricato_da = models.ForeignKey(
|
||||
User, on_delete=models.SET_NULL, null=True, related_name='documenti_caricati'
|
||||
)
|
||||
data_caricamento = models.DateTimeField(auto_now_add=True)
|
||||
conversazione = models.ForeignKey(
|
||||
'Conversazione', on_delete=models.SET_NULL, null=True, blank=True, related_name='documenti'
|
||||
)
|
||||
obiettivo = models.ForeignKey(
|
||||
'Obiettivo', on_delete=models.SET_NULL, null=True, blank=True, related_name='documenti'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-data_caricamento']
|
||||
verbose_name = 'Documento'
|
||||
verbose_name_plural = 'Documenti'
|
||||
|
||||
def __str__(self):
|
||||
return self.titolo
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
import os
|
||||
return os.path.basename(self.file.name)
|
||||
|
||||
Reference in New Issue
Block a user