Django intersection based on common field - django

I have chat and participant models.
class Chat(models.Model):
...
class Participant(models.Model):
chat = models.ForeignKey(Chat, on_delete=models.CASCADE, related_name='participants')
participant = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
...
I'm looking for a way to check if there exists a single chat with two specified users.
Edit: I've thought of using "in" on the nested objects but am unsure how to require both.
qs = Chat.objects.filter(participants__participant__in[user_a,user_b])
This query selects each chat the participant is in but I want only the chats where both participants are in

You can chain calls to filter which will and your filter conditions:
qs = Chat.objects.filter(
participants__participant=user_a
).filter(
participants__participant=user_b
)

Below is the query which can be used in the required view or model definition.
Filter the chat items with user A
Filter the chat user B with chat__pk in first query set
qs_first = Chat.objects.filter(
participants__participant = user_a).values('pk')
qs_second = Chat.objects.filter( pk__in = qs_first,
participants__participant = user_b)
This is considering user_a and user_b are a objects of the CustomUser class.

Related

Django Model queries with relationships. How to do the right join

Let's say I have 2 Models:
class Auction(models.Model):
seller = models.ForeignKey(User, on_delete=models.CASCADE, related_name="seller")
title = models.CharField(max_length=64)
class Watchlist(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_watchlist')
auction = models.ForeignKey(Auction, on_delete=models.CASCADE, related_name='auction_watchlist')
The view receives a request, creates a context variable with the auction objects the are:
associated with the user who made the request and
that have been added to the Watchlist Model,
sends it to the template.
I have set up my view to work like this:
#login_required
def watchlist(request):
watchlist_objects = Watchlist.objects.filter(user=request.user)
auction_objects = Auction.objects.filter(auction_watchlist__in=watchlist_objects).all()
context = {'watchlist_auctions': auction_objects}
print(context)
return render(request, "auctions/watchlist.html", context)
-I make the first query to get the list of items in the watchlist associate with the user.
-Then I use that to get another query from the Auction Model and I pass it to the template.
In the template I can access the attributes of Auction to display them. (title, author, and others that I did not include for simplicity)
The question is:
Is this the "right way? Is there a better way to access the attributes in Auction from the first Watchlist query?
It seems to me that I'm doing something overcomplicated.
This is not that bad, considering that it will probably be executed as one query, because of the lazy queryset evaluations. You can skip the .all() if you already have .filter().
However, there is a more convenient way to do this, using lookups that span relationships.:
auction_objects = Auction.objects.filter(auction_watchlist__user_id=request.user.id)

Django two parameter filter query with foreign key

My Django models look like this:
class User(models.Model):
userid = models.CharField(max_length=26,unique=True)
#some more fields that are currently not relevant
class Followers(models.Model):
user = models.ForeignKey('User',related_name='usr')
coins = models.IntegerField()
followers = models.CharField(max_length=26, null=True, blank=True)
I would now like to make a filter query in my Followers table selecting every entry where users have ID x and followers have ID y (I expect to get one result from the query).
To visualize what I have tried and know won't work is this:
queryfilter = Followers.object.filter(followers=fid, user=uid)
and this:
queryfilter = Followers.object.filter(followers=fid, user__userid=uid)
In the end I would like to access the coins:
c = queryfilter.coins
It may be possible that I cannot do it with one single query and need two, since I am trying to do a filter query with two tables involved.
Firstly, I have modified your 'Followers' model (for naming convention).
models.py
class Follower(models.Model):
user = models.ForeignKey('User', related_name='followers')
coins = models.IntegerField()
key = models.CharField(max_length=26, null=True, blank=True)
Your queryset should be ..
views.py
#coins
coins = Follower.objects.filter(key=fid, user__userid=uid).get().coins

Django getting database fields with one query

I have a few models in django (User(standard), Member(extended user), Calculations, Subscription, Type) as follows :
class Member(models.Model):
user = models.ForeignKey(to=User)
..........
class Calculations(models.Model):
user = models.ForeignKey(to=User)
.....
class Type(models.Model):
limit = models.IntegerField()
name = models.CharField(max_length=50)
default = models.BooleanField()
class Subscription(models.Model):
started = models.DateField()
type = models.ForeignKey(Type)
member = models.OneToOneField(Member)
Thus,
Calculations is connected to User with ForeignKey
Member is also connected to user with ForeignKey
Subscriptions is connected to Member and with Type with ForeignKey
In my view I want to query the database and to access information from all those models.
Thus I want all members except the currently logged in, and I want to get the number of the calculations and the type of the subscription.
I'm trying to do it with one query.
I tried something like :
#login_required
def members(request):
// That's how I get all information about user and members, but I also need the calculation and subscription
members_list = Member.objects.select_related('user').all().exclude(user=request.user)
context = {'members': members_list}
return render(request, 'master/members.html', context)
Any advice how can I do that?
Access all elements from related Models.
qv = Member.objects.exclude(user=request.user).values('user__subscription__started', 'user', 'user__calculations__user')

Create Django Table displaying information about users

I am currently using django 1.8 and I'd like to create a more intelligent way to display information about users. Say I have something like this:
class User(models.Model):
name = models.CharField()
class Invitation(models.Model):
inviter = models.ForeignKey(User)
invitee = models.ForeignKey(User)
I want to create a field that is the unique number of user's an inviter has invited. I could see how this could be done with something like set("SELECT invitee FROM INVITATIONS WHERE inviter = 'my-user';"), but if I want this displayed in the admin panel, is there a simple way to present this?
Also, I would want this done for every user, so it feels like there is a simple way to make a field generated for every user in the table.
First, let's setup proper related_name- it'll help reduce a lot of confusion in the code.
class Invitation(models.Model):
inviter = models.ForeignKey(User, related_name="invitation_sent")
invitee = models.ForeignKey(User, related_name="invitation_recv")
With the related_name setup, we can do queries such as
user = User.objects.get(pk=1)
# retrieve all invitation objects sent by this user
user.invitation_sent.all()
# retrieve all invitation objects received by this user
user.invitation_recv.all()
Now we can actually count the number of unique invitations a user has sent out quite easily:
# count number of distinct invitee for user
user.invitation_sent.all().values('invitee').distinct().count()
Next, we can actually count the number of unique users a user has invited in a single database query for all users:
user_list = User.objects.all().annotate(
uniq_inv=Count('invitation_sent__invitee', distinct=True)
)
Each user object returned will have an additional property called uniq_inv which contains the count of unique users the user has invited
for user in user_list:
print(user.name + ' invited ' + user.uniq_inv + ' unique users')
To apply this to the admin interface, you'll need to override get_queryset method:
class MyAdmin(admin.ModelAdmin):
...
list_display = [..., 'uniq_inv']
def uniq_inv(self, obj):
return obj.uniq_inv
uniq_inv.short_description = 'Unique Invitees'
def get_queryset(self, request):
qs = super(MyAdmin, self).get_queryset(request)
qs = qs.annotate(uniq_inv=Count('invitation_sent__invitee', distinct=True))
return qs
You can use annotate, which allows to add calculated fields to a queryset.
Models:
class User(models.Model):
name = models.CharField()
class Invitation(models.Model):
inviter = models.ForeignKey(User,related_name="inviter_user")
invitee = models.ForeignKey(User,related_name="invited_user")
Queryset:
from django.db.models import Count
q = Invitation.objects.annotate(count_invitee=Count('invitee')).all()
Now "count_invitee" field has the number for each invitation object.
If you want to filter invitee from the user side.
For a single user:
User.objects.get(pk=1).invited_user.all.count()
For all users queryset:
User.objects.annotate((count_invitee=Count('invited_user')).all()

Fetching data from Django models related via foreign key

I have a model in Django that looks like this (I've simplified the tables & skipped the irrelevant fields. I can't change the tables/relations):
Class Attachment(models.Model):
name = models.CharField()
Class Email(models.Model):
subject = models.CharField()
from = models.ForeignKey(User)
attach = models.ForeignKey(Attachment)
Class User(models.Model):
name = models.CharField()
In my view, I want to find all the Users that have sent this attachment. So, first I fetch all the emails that contain the this attachment
my_attachment = Attachment.objects.get(name='Picture1.jpg')
email_set = my_attachment.email_set.all()
What's an efficient way to fetch all the users that are listed in the from field of emails in email_set i.e. without looping through email_set.
This is the easy and efficient way:
users = ( User
.objects
.filter( email__attachment__name = 'Picture1.jpg' )
.distinct()
)
Remember to create needed indexes to your database tables.