'How to make a query on related_name field?

I have to models connected by a ForeignKey

class User(AbstractUser):
   ...

and

class PrivateMessage(models.Model):
    user_from = models.ForeignKey(
        User,
        verbose_name=u'From',
        related_name='sent_messages',
    )
    user_to = models.ForeignKey(
        User,
        verbose_name=u'To',
        related_name='received_messages',
    )

Is there any way to get all the addresses for a particular user. For example, if

u = User.objects.get(id=1)
messages = PrivateMessage.objects.filter(user_from=u)
for m in messages:
    users.add(m.user_to)

How to obtain a list of users that appear in user_to for these messages using only Django ORM methods?



Solution 1:[1]

Finally, I ended up writing three queries:

    users_from = set(PrivateMessage.objects.filter(
        user_to=self.request.user,
    ).values_list(
        'user_from__pk',
        flat=True,
    ))
    users_to = set(PrivateMessage.objects.filter(
        user_from=self.request.user,
    ).values_list(
        'user_to__pk',
        flat=True,
    ))
    interlocutors = User.objects.filter(pk__in=users_from.union(users_to))

Solution 2:[2]

I think a better idea would be to define ManyToManyField on the User model:

class User(AbstractUser):
    #...
    receivers = models.ManyToManyField('self', through='Message',
                                      symmetrical=False, related_name="senders")

class Message(models.Model):
    user_from = models.ForeignKey(MyUser, related_name='messages_from')
    user_to = models.ForeignKey(MyUser, related_name='messages_to')
    message = models.CharField(max_length=100, default="")
    #...

Then to retrieve users list on the other end you simply do:

User.objects.get(id=1).receivers.all()  # who I sent the message to
User.objects.get(id=1).senders.all()    # who sent me a message

This way you have a nice clear API.

Solution 3:[3]

I saw this docs

Maybe you can try:

u = User.objects.get(id=1)
users = User.objects.filter(received_messages__user_from=u).distinct()

Solution 4:[4]

related_name field makes our queries especially the ones using foreign key (on to many relation) easier, shorter and cleaner.

Let say we have 2 models classes Library and Book.

class Library(Models.model): name = models.CharField(max_length = 100)

`class Book(Models.model):
    title = models.CharField(max_length = 100)
    library = models.ForeignKey(Library, 
                                on_delete = models.CASCADE, 
                                related_name = 'books')`

Here we have a one to many relation from Library to Book using foriegn key. And in my django shell. I can create a new Library and a book related to that library in the following manner.

`from <app_name>.models import *` 
`library = Library.objects.create(name = 'Big Library')`
`Book.objects.create(title = 'Awesome book', library = library`

Now I can query the book of the library using related name of model Book class:

`library.books.all()`

rather than using the starting the query from Book model as:

Book.objects.filter(library = library)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 cansadadeserfeliz
Solution 2 mariodev
Solution 3 Leandro
Solution 4