Search code examples
djangodjango-modelsdjango-admindjango-managers

Recursive relationship in Django: get all the interrelated records from each record


I have this model for a tune:

class MsTune(models.Model):

    name = models.CharField(max_length=255)
    ms = models.ForeignKey(Manuscript, on_delete=models.CASCADE, related_name="mstunes")
    concordances = models.ManyToManyField("self", blank=True)

I have many manuscripts (ms), and the same tune might appear in more than one manuscript. What I want to do, with that concordances field, is link all the similar tunes. This works, in part. The Django administration back-end allows me to select many tunes to be linked to the current one I'm editing:

enter image description here

The problem is that I'd like to see ALL the tunes I've linked in EACH of the tune. For instance, in the example above, Mary Scott... should list all three tunes (Courante, Almain, Hopetounsetc...); Courante should list the other three (Mary Scott, Almain, Hopetoun's). Right now they only show the one from which editing page I've added them. What am I missing? Do I have to create a new concordances model?

PS

Specifying symmetrical=True doesn't help.

Better explanation of what I want to achieve

If I have these tunes:

tune_1
tune_1a
tune_1b
tune_2

Right now I'm getting this:

tune_1:
concordances.all: tune_1a, tune_1b

tune_1a:
concordances.all: tune_1

tune_1b:
concordances.all: tune_1

I want this:

tune_1:
concordances.all: tune_1a, tune_1b

tune_1a:
concordances.all: tune_1, tune_1b

tune_1b:
concordances.all: tune_1, tune_1a

Partial solution with intermediary model

Let's say I use an intermediary model:

class MsTune(models.Model):

    related = models.ManyToManyField('MsTune', through='Concordance', blank=True)
[...]

class Concordance(models.Model):
    tune = models.ManyToManyField(MsTune)
    title = models.CharField(max_length=64)

    def __str__(self):
        return self.title

How do I then access the list of interrelated tunes in a template where I'm displaying the details of a specific tune?

{% for concordance in tune.concordance_set.all %} {{ concordance__mstune_id }}{% endfor %}

Doesn't output anything; and [...]{{ concordance }}[...] outputs the name of the concordance, not the title of each tune.

Accessing {{ tune.concordances }} gives me a 'ManyToManyField' object has no attribute '_m2m_reverse_name_cache' error.


Solution

  • I solved by creating a different model:

    class Concordance(models.Model):
        name = models.CharField(max_length=64)
        tunes = models.ManyToManyField(MsTune, related_name="concordances")
    
        def __str__(self):
            return self.name