I am trying to add simple user to user messaging functionality to my blog app in Django. I have a view that allows a user to send a message but I am having difficulty in displaying the messages after. Here is my Message model:
class Message(models.Model):
user = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='messages')
sender = models.ForeignKey(Profile, on_delete=models.CASCADE, related_name='messages_from')
message = models.TextField(blank=True)
timestamp = models.DateTimeField(default=timezone.now, editable=False)
unread = models.BooleanField(default=True)
And the related Profile model:
class Profile(models.Model):
first_name = models.CharField(max_length=100, blank=True)
last_name = models.CharField(max_length=100, blank=True)
user = models.OneToOneField(User, on_delete=models.CASCADE)
slug = models.SlugField(unique=True, blank=True)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True)
Here is my MessagesView attempt:
class MessagesView(ListView):
model = Profile
template_name = 'users/messages.html'
context_object_name = 'msg'
def get_queryset(self):
return Profile.objects.filter(messages_from__isnull=False, messages__user_id=self.request.user)
And here is the url:
path('messages/<int:pk>/', MessagesView.as_view(), name='messages'),
Upon trying to load this page I receive the error Cannot query "user": Must be "Profile" instance
where "user" is the name of the logged in user who's messages I am attempting to load. I have spent a long time googling a solution to this but have found nothing that relates to my case. Please help
Your Message
has as user
field a ForeignKey
to Profile
, not User
(therefore it might be better to rename the field to profile
). This thus means that filtering like messages__user_id=self.request.user
does not make much sense.
You can filter by following the relation from Profile
to User
with:
class MessagesView(ListView):
model = Profile
template_name = 'users/messages.html'
context_object_name = 'msg'
def get_queryset(self):
return Profile.objects.filter(
messages_from__isnull=False,
messages__user__user=self.request.user
).distinct()
The .distinct()
[Django-doc] is necessary here to prevent retrieving the same Profile
multiple times.
Since this is a MessagesView
, you furthermore probably should return Message
s, the fact that you set the context_object_name
to msg
also hints to that. In that case you thus should return a QuerySet
of Message
s, not Profile
s:
class MessagesView(ListView):
model = Message
template_name = 'users/messages.html'
context_object_name = 'msg'
def get_queryset(self):
return Message.objects.filter(
user__user=self.request.user
)
In case you rename the ForeignKey
to profile
, you filter with profile__user=self.request.user
.
Note: You can limit views to a class-based view to authenticated users with the
LoginRequiredMixin
mixin [Django-doc].
Note: It is normally better to make use of the
settings.AUTH_USER_MODEL
[Django-doc] to refer to the user model, than to use theUser
model [Django-doc] directly. For more information you can see the referencing theUser
model section of the documentation.