Synonymous many to many model relationship in Django

django needs to have a value for field "id" before this many-to-many relationship can be used.
django model inheritance
django many-to-many multiple models
many-to-many relationship in python
one to many relationship example in django
django many-to-many performance
django proxy model
django manytomanyfield choices

I'm trying to achieve what you could call a "synonymous" relationship on a self referencing many to many field in Django.

Take this model for example (in reality I don't use real words, but category tags instead):

class Word(models.Model):
    name = models.CharField(max_length=30, unique=True)
    synonymous = models.ManyToManyField('self', blank=True,  related_name='synonymous')

    def __str__(self):
        return self.name

What I want to achieve, is when I have 3 objects, and add any combination of them to the synonymous field, I want all of them to be connected.

# Create synonymous words
bunny = Word.objects.create(name='bunny')
hare = Word.objects.create(name='hare')
rabbit = Word.objects.create(name='rabbit')
# Set synonymous words to rabbit
rabbit.synonymous.set([bunny, hare])

Now when I get the synonymous objects of rabbit, it has what I want:

(Pdb) rabbit.synonymous.all()
<QuerySet [<Word: bunny>, <Word: hare>]>

But when I take the synonymous objects of bunny and hare, they only return rabbit.

(Pdb) bunny.synonymous.all()
<QuerySet [<Word: rabbit>]>
(Pdb) hare.synonymous.all()
<QuerySet [<Word: rabbit>]>

What I'd like to achieve, is all the synonymous objects, to be "symmetrical". Now, the m2m field is already symmetrical, but it only stops at one object, not all given synonymous objects.

So, the ideal result would be this:

# Create synonymous words
bunny = Word.objects.create(name='bunny')
hare = Word.objects.create(name='hare')
rabbit = Word.objects.create(name='rabbit')
# Set synonymous ON ONE WORD
rabbit.synonymous.set([bunny, hare])

# And now ALL the objects, which have at least ONE related synonym, would automatically be assigned to the other words as well
(Pdb) rabbit.synonymous.all()
<QuerySet [<Word: bunny>, <Word: hare>]>
(Pdb) hare.synonymous.all()
<QuerySet [<Word: bunny>, <Word: rabbit>]>
(Pdb) bunny.synonymous.all()
<QuerySet [<Word: rabbit>, <Word: hare>]>

I hope that was clear.

I'm wondering whats the cleanest way to achieve this? Perhaps there is some way to do it through the ORM, but I'm having doubts.

Am I best off just writing a signal that manages those relationships manually?


Multiple self referenced ForeignKey relationship fields in Django , That means that a word can have multiple homonyms, synonyms and antonyms, like: class WordCoreModel(models.Model, BaseModel):� Many-to-many relationships ¶. Many-to-many relationships. ¶. To define a many-to-many relationship, use ManyToManyField. In this example, an Article can be published in multiple Publication objects, and a Publication has multiple Article objects: from django.db import models class Publication(models.Model): title = models.CharField(max_length=30) class Meta: ordering = ['title'] def __str__(self): return self.title class Article(models.Model): headline = models.CharField(max_length=100)


I think the simplest way to achieve this is through the code below:

for word in synonymous:
    word.synonymous.set(synonymous.exclude(pk=word.pk))

Edit

The best spot to place this code is within your views.py. If you're using Django Admin, you should use save_related.

Synonymous many to many model relationship in Django, I'm trying to achieve what you could call a “synonymous” relationship on a self referencing many to many field in Django. Take this model for� For example – a model Book has many-to-many relationship with a model Author, i.e. an book can be written by multiple authors and an author can write multiple books. Many-to-many relations are defined using ManyToManyField field of django.db.models. Below is an example to demonstrate the same.


As heemayl mentioned, there is no way to do it directly through the ORM.

So I ended up making 2 functions, one for getting/finding all the synonymous relationships, and the other for setting/syncing them

For getting/finding:

def get_all_synonymous_words(word):
    # Start with the word's own synonymous words, and their synonymous words
    found_syn_ids = set(word.synonymous.values_list('id', flat=True)) | set(word.synonymous.values_list('synonymous', flat=True))

    while found_syn_ids:
        words = Word.objects.filter(id__in=found_syn_ids)
        batch_syn_ids = set(words.values_list('synonymous', flat=True))

        # If the batch syn ids are equal to last batch ids, all relationships found
        if batch_syn_ids == found_syn_ids:
            return batch_syn_ids

        found_syn_ids = batch_syn_ids

For setting/syncing:

def set_all_synonymous_words(word):
    syn_ids = get_all_synonymous_words(word)
    if syn_ids:
        syn_qs = Word.objects.filter(id__in=syn_ids)
        for word in syn_qs:
            # Exclude current word to not self reference
            excluded_qs = syn_qs.exclude(id=word.id)
            if not set(word.synonymous.exclude(id=word.id)) == excluded_qs:
                word.synonymous.set(excluded_qs)

This way, when you update/create words, you can find all the combinations, and update them, without having a list of the synonyms pre-defined.

As I use the django-rest-framework, I call it out in views, by overriding the perform_update/perform_create methods:

    def perform_update(self, serializer):
        serializer.save()

        # Get the updated word, and sync the synonymous words to be all symmetrical
        set_all_synonymous_words(Word.objects.get(id=serializer.data['id']))


    def perform_create(self, serializer):
        serializer.save()

        # Get the updated word, and sync the synonymous words to be all symmetrical
        set_all_synonymous_words(Word.objects.get(id=serializer.data['id']))

Or you can call it out manually:

    # Create synonymous words
    bunny = Word.objects.create(name='bunny')
    hare = Word.objects.create(name='hare')
    rabbit = Word.objects.create(name='rabbit')
    # Set synonymous
    rabbit.synonymous.set([bunny, hare])
    # Sync synonymous
    set_all_synonymous_words(bunny)

#12641 (ManyToMany relationship with self, symmetrical=True , class Tag(models. list with the difference that these is a many to many relationship. Since there is also something like synonyms treebear and mptt are not Django models support the same three relationships supported by relational database systems: One to many, many to many and one to one. One to many relationships in Django models. A one to many relationship implies that one model record can have many other model records associated with itself.


Many-to-many relationships | Django documentation, To define a many-to-many relationship, use ManyToManyField . In this example, an from django.db import models class Publication(models.Model): title� Here we define a relationship where a club has many Persons and members and a Person can be a member of several different Clubs. Though we define only two models, django actually creates three tables in the database for us.


Many-to-one relationships | Django documentation, Many-to-one relationships�. To define a many-to-one relationship, use ForeignKey : from django.db import models class Reporter(models.Model): first_name� How to Implement One-To-Many Relationship in Django Django newbies seem to have a hard time understanding the relationships between models and why it matters. Maybe, as a newbie, you associate a database the same way that you associate a spreadsheet… just a place for storing information.


Relationships in Django models, Many to many relationships in Django models For example, Store model records can have many Amenity records, just as Amenity records can belong to many Store records. To define a many to many relationship in Django models you use the ManyToManyField data type. When different entities of an application have a many-to-many relationship between them, the relationship can be modeled as an adjacency list. In this pattern, all top-level entities (synonymous to nodes in the graph model) are represented using the partition key.