How do I attach an instance-specific queryset to a model in Django?

Go To StackoverFlow.com

0

I am making a very minimal user-to-user messaging app using Django 1.4. I want to fetch unread messages that a user received in a straightforward way from my templates. My model looks something like this:

from django.contrib.auth.models import User

class Message(models.Model):
    sender = models.ForeignKey(User, related_name='messages_sent')
    receiver = models.ForeignKey(User, related_name='messages_received')
    read = models.BooleanField(default=False)

Now I can easily access the messages that a user has received from user.messages_received. I'd like to filter this queryset, though, to quickly access the unread messages in an easy way. I know that I can always filter the queryset user.messages_received.filter(read=False), but I'd like to get at them directly in templates, possibly like this:

<a href="{% url inbox %}"> Inbox ({{ user.unread_messages.count }})</a>

I suspect I want to make a Manager, but I'm not sure how to write it or where to attach it.

Thanks in advance.

2012-04-04 02:29
by jreyes


1

There are two ways to accomplish this that come to my mind.

First, you could extend the user model with a custom function.

from django.contrib.auth.models import User

def unread_messages(self):
    return self.messages_received.filter(read=False)
User.add_to_class('unread_messages', unread_messages)

But that is slightly hacky. The "clean" way would be not to extend the User model directly, but to create a UserProfile for your users and add the function there. The docs describe this quite well.

In your case:

models.py

from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    def unread_messages(self):
        return self.user.messages_received.filter(read=False)

settings.py

AUTH_PROFILE_MODULE = 'appname.UserProfile'

template

{{ user.get_profile.unread_messages.count }}

The code is untested, but should work :)

2012-04-04 09:53
by Danilo Bargen
Thanks, I can easily add that to my user profile model. I'm a little hesitant, though. My profile model is in a different app than my message app, and I was hoping not to mix the two. But this certainly works - jreyes 2012-04-04 23:19
You could also solve it via a custom template filter that gets the count for a user passed as the parameter. But I'm not sure whether that's a cleaner solution, probably not : - Danilo Bargen 2012-04-05 13:05
And if you decorate unread_messages with @property, you do no longer need () for calling it and it will look a lot as if it were in fact a Manager - Lutz Prechelt 2016-04-21 08:27