I have some trouble trying to fetch some manytomanyrelated data in by Django Application
Here is my model :
SoftwareVersion(models.Model):
id = models.AutoField(
primary_key=True,
db_index=True
)
... Some other fields ...
incompatibilities= models.ManyToManyField(
"self",
symmetrical=True,
blank=True,
default=None,
through="Incompatibilities"
)
Incompatibilities(models.Model):
id = models.AutoField(
primary_key=True,
db_index=True
)
softwareversion_a = models.ForeignKey(
"SoftwareVersion",
models.CASCADE,
db_index=True,
db_column='softwareversion_a ',
related_name='softwareversion_a',
verbose_name="software version a",
)
softwareversion_b = models.ForeignKey(
"SoftwareVersion",
models.CASCADE,
db_index=True,
db_column='softwareversion_b',
related_name='softwareversion_b',
verbose_name="softwareversion_b",
)
status = models.BooleanField(
verbose_name='Status',
default=False
)
class Meta:
unique_together = (('softwareversion_a', 'softwareversion_b'),)
To this I add in the SoftwareVersion's save method a logic to create related Incompatibilities for each new software version. I have tried several way to do it (with a loop or with a bulk_create) here is the bulk create function i use :
# Inside SoftwareVersion Model class
def save(self, force_insert=False, force_update=False, using=None, update_fields=None) -> None:
save = super().save(force_insert, force_update, using, update_fields)
Incompatibilities.objects.bulk_create(
(Incompatibilities(
softwareversion_a=self,
softwareversion_b=software_version,
status=False
) for software_version in SoftwareVersion.objects.exclude(self)),
ignore_conflicts=True,
batch_size=1000
)
return save
First problem I have is this method ignore the unique_together constraint, it creates duplicates. Before i was using a loop on each SoftwareVersion to create an object but it was too long so i wanted to use bulk_create but it seems to not work as i intended. Is there another optimized way to do it or a parameter to pass so that the unique together constraints is respected.
Secondly, what is the most optimized way to query "Give all the incompatibilities for this software version". Currently i am doing this :
Incompatibilities.objects.filter(softwareversion_a=?)
But i actually miss the incompatibilities which reference the software version in the field "softwareversion_b". I have tried to use the logic :
VersionLogiciel.objects.get(pk=?).incompatibilities.all()
But django output the same SQL request and so, the same result.
Incompatibilities.objects.filter(softwareversion_a=?)
Is there a parameter to put somewhere so that two field (here 'softwareversion_a', 'softwareversion_b') can be interchangeable. Or maybe i have to query in a particular way to access to the incompatibilities objects. I have tried querying :
Incompatibilities.objects.filter(Q(softwareversion_a=?) or Q(softwareversion_b=?))
But since i have to order result on softwareversion_a related fields and softwareversion_b related field i can't get it working like i want.
PS : Sorry for my bad english and notice that i translated the model to english so i may i have done some mistakes but on my side the model compilation and migrations is working as intended.
Thanks in advance for any help.
I end up opting for the second solution here : https://charlesleifer.com/blog/self-referencing-many-many-through/
Instead of adding methods to my django model i deside to create postgres Trigger with django-pgtrigger. My trigger permit to replicate update, insert and delete. To avoid recursion i add a "if exist" verification to avoid updating already up to date data (same for insert and delete).