I have a web-based chat app developed in Django. People can form their own chat groups in it, invite others and chatter away in the said groups.
I want to isolate all users who were recently online AND: (i) have already been sent an invite for a given group, OR (ii) have already participated (i.e. replied) at least once in the same given group. Note that user
is a vanilla django.contrib.auth
user
.
To accomplish this, I'm writing:
online_invited_replied_users = User.objects.filter(id__in=recently_online,(Q()|Q()))
Assume recently_online
to be correctly formulated. What should be the two Q objects?
The first Q()
ought to refer invitees
, the second to users who have replied at least once. I seem to be running into code-writer's block in formulating a well-rounded, efficient db query here. Please advise!
Relevant models are:
class Group(models.Model):
topic = models.TextField(validators=[MaxLengthValidator(200)])
owner = models.ForeignKey(User)
created_at = models.DateTimeField(auto_now_add=True)
class GroupInvite(models.Model):
#this is a group invite object
invitee = models.ForeignKey(User, related_name='invitee')
inviter = models.ForeignKey(User, related_name ='inviter')
sent_at = models.DateTimeField(auto_now_add=True)
which_group = models.ForeignKey(Group)
class Reply(models.Model):
#if a user has replied in a group, count that as participation
text = models.TextField(validators=[MaxLengthValidator(500)])
which_group = models.ForeignKey(Group)
writer = models.ForeignKey(User)
submitted_on = models.DateTimeField(auto_now_add=True)
Note: feel free to ask for more info; I'm cognizant of the fact that I may have left something out.
For users that are already invited to a group group
, follow the GroupInvite.invitee
foreign key backwards.
already_invited = Q(invitee__which_group=group)
The related_name you chose, invitee
, doesn't really make sense, because it's linking to an group invite, not a user. Maybe `group_invites_received' would be be better.
For users that have already replied, follow the Reply.writer
foreign key backwards.
already_replied = Q(reply__which_group=group)
In this case it's reply
. because you haven't specified a related name.
Note that your current pseudo code
User.objects.filter(id__in=recently_online,(Q()|Q()))
will give an error 'non-keyword arg after keyword arg'.
You can fix this by either moving the non-keyword argument before the keyword argument,
User.objects.filter((Q()|Q()), id__in=recently_online)
or put them in separate filters:
User.objects.filter(id__in=recently_online).filter(Q()|Q())
Finally, note that you might need to use distinct()
on your queryset, otherwise users may appear twice.