Hello à tous,
Je suis en train de me prendre la tête sur mon projet actuel. C’est une application qui permet de gérer une ICD et ses versions. En gros l’utilisateur rentre les différents équipements qui composent le réseau avec ses données (adresse IP, MAC…) ainsi que les messages échangés entre ces équipements et il peut générer la documentation ou des fichiers de configuration automatiquement.
Ça, ça fonctionne. Maintenant il faut pouvoir gérer des versions de cette ICD. Tous les modèles héritent d’un VersionnedModel:
class VersionManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(version__id=get_current_version_id())
class VersionnedModel(BaseModel):
version = models.ForeignKey(Version, on_delete=models.CASCADE)
versionned_objects = VersionManager()
objects = models.Manager()
class Meta:
abstract = True
def save(self, *args, **kwargs):
if self.version.frozen:
raise ValueError("Cannot modify a frozen version")
if not self.version:
self.version = get_current_version()
super(VersionnedModel, self).save(*args, **kwargs)
class Version(BaseModel):
edition = models.PositiveIntegerField(unique=True, validators=[MinValueValidator(1)])
description = models.TextField(blank=True, null=True, default=None)
frozen = models.BooleanField(default=False)
def __str__(self):
return str(self.edition)
Quand l’utilisateur veut créer une nouvelle version, il a la possibilité de le faire à partir d’une ancienne version et donc de dupliquer l’entièreté des données d’une version précédente vers la nouvelle version. Et là vient le problème : comment dupliquer toutes les données liées à une version tout en gérant les relations multiples entre les modèles ? (Dont des relations qui partent et pointent vers un même modèle !).
Voici un exemple de modèles:
class InetAddress(VersionnedModel):
value = models.GenericIPAddressField()
objects = models.Manager()
class Meta:
unique_together = [('value', 'version')]
def __str__(self):
return str(self.value)
class Device(VersionnedModel):
name = models.CharField(max_length=255)
mac_address = models.CharField(max_length=17, validators=[validators.validate_unique_mac_address])
inet_address = models.OneToOneField(InetAddress, on_delete=models.CASCADE)
objects = models.Manager()
class Meta:
unique_together = [('name', 'version'), ('mac_address', 'version')]
def __str__(self):
return self.name
class PhysicalPort(VersionnedModel):
index = models.PositiveIntegerField(validators=[MinValueValidator(1)])
device = models.ForeignKey(Device, on_delete=models.CASCADE, related_name='ports')
connected_to = models.OneToOneField('self', blank=True, null=True, default=None, on_delete=models.SET_NULL)
tag_vlan = models.ForeignKey('VLAN', related_name='tagged_ports', blank=True, null=True, default=None, on_delete=models.SET_NULL)
objects = models.Manager()
class Meta:
unique_together = [('index', 'device')]
def __str__(self):
return f'{self.device}:{self.index}'
class VLAN(VersionnedModel):
name = models.CharField(max_length=255)
tag = models.PositiveIntegerField()
devices = models.ManyToManyField(Device, blank=True, related_name='vlans')
objects = models.Manager()
class Meta:
verbose_name = 'VLAN'
verbose_name_plural = 'VLANs'
unique_together = [('name', 'version'), ('tag', 'version')]
def __str__(self):
return self.name
class DestinationGroup(VersionnedModel):
name = models.CharField(max_length=255)
inet_address = models.OneToOneField(InetAddress, on_delete=models.CASCADE, related_name='destination_group')
vlan = models.ForeignKey(VLAN, on_delete=models.CASCADE, related_name='destination_groups')
members = models.ManyToManyField(Device, blank=True, related_name='destination_groups')
objects = models.Manager()
class Meta:
unique_together = [('name', 'version')]
def __str__(self):
return self.name
Il y en a d’autre dont des modèles avec des relations polymorphiques… (pour gérer les messages et les différents types de champs qu’un message peut avoir).
Quelle serait la bonne approche à ce problème ? En gros dupliquer toutes les données, mettre à jour la version et les differents ID des relations vers celles créées.
Merci pour vos conseils!