Shivam Kumar Shivam Kumar - 8 months ago 132
Python Question

Filtering Distinct and Ordered Data

I'm trying to create a messaging App where user can see the list of people who messaged him & also whom he messaged, so that he can click on their names & see the conversation occurred.
Problem is that I couldn't filter out the distinct & ordered list of users who messaged request.user or whom request.user messaged.

Here's the Model,

class Message(models.Model):
sender = models.ForeignKey(User, related_name="sender")
receiver = models.ForeignKey(User, related_name="receiver")
msg_content = models.TextField(max_length=8000)
created_at = models.DateTimeField(auto_now_add=True)


This is what I tried in view,

def profiles(request):
users = Message.objects.filter(Q(sender=request.user) | Q(receiver=request.user)).values('sender__first_name', 'receiver__first_name', 'receiver__id', 'sender__id').annotate(Max('id')).order_by('-id__max')
return render(request, 'chat/users.html', {'users': users})


Here's the template,

{% for user in users %}
{% if user.sender__id != request.user.id %}
{{ user.sender__first_name }}
{% else %}
{{ user.receiver__first_name }}
{% endif %}
{% endfor %}


This code seems working fine but it's returning the same user twice as long as request.user sent him a message & he replies back to it.

How can I solve this issue? Thank You . . .

Answer Source

You can use a set() to get unique users. Though I'm not sure if there's a more efficient way.

def profiles(request):
    users = set()
    for message in Message.objects.filter(Q(sender=request.user) | Q(receiver=request.user)):
        if message.sender != request.user:
            users.add(message.sender)
        if message.receiver != request.user:
            users.add(message.receiver)
    users = list(users)
    return render(request, 'chat/users.html', {'users': users})

And change in your template accordingly.

{% for user in users %}
    {% if user.id != request.user.id %}
        {{ user.first_name }}
    {% endif %}
{% endfor %}

EDIT: If you want the users to be ordered based on the time most recently interacted then use OrderedDict.

def profiles(request):
    from collections import OrderedDict
    users = OrderedDict()
    for message in Message.objects.filter(Q(sender=request.user) | Q(receiver=request.user)).order_by('-created_at'):
        if message.sender != request.user and message.sender not in users.keys():
            users[message.sender] = message.sender
        if message.receiver != request.user and message.receiver not in users.keys():
            users[message.receiver] = message.receiver
    return render(request, 'chat/users.html', {'users': users})

And in template do as follows.

{% for user in users.values %}
    {% if user.id != request.user.id %}
        {{ user.first_name }}
    {% endif %}
{% endfor %}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download