Select values from two tables using Django - django

I have two tables as follows,
cabinet
cabinet_id cabinet_name
1 Test1
2 Test2
3 Test3
cabinet_maping
id product_id cabinet_id size
1 34 1 20
2 34 3 25
How can I select all cabinet_name from cabinet table where cabinet_maping.product_id = 34 in Django
Expected Output as follows,
cabinet_id cabinet_name size
1 Test1 20
2 Test2 0
3 Test3 25

I think that yours models could look like
class Cabinet(models.Model):
name = models.CharField(max_length = 30)
class cabinet_maping(models.Model):
product = models.ForeignKey(Product)
cabinet = models.ForeignKey(Cabinet)
size = .....
You should do sth like this:
cabinet_name = cabinet_maping.objects.filter(product__id = 34)
for item in cabinet_name:
print item.cabinet.id
print item.cabinet.name
print item.size
I didn't check it but i think that should work (that works :))

I agree with Silwestpl that your models are wrong as using Foreign Key would make this query a lot easier. But just an answer to your question would be. I am assuming that you dont have any relationships between the two tables as you haven't mentioned any.
x = Cabinet_mapping.objects.filter(product_id = somevalue).distinct('cabinet_id')
response_list = []
for y in x:
response_dict = {}
response_dict['cabinet_id'] = y.cabinet_id
response_dict['cabinet_name'] = cabinet.objects.get(id = y.cabinet_id).cabinet_name
response_dict['size'] = y.size
response_list.append(response_dict)
return response_list
This would be the answer according to the details you have provided.
But Ideally I would do something like this
class Product(models.Model):
# id is generated automatically.
## any other fields that you want for product.
class Cabinet(models.Model):
# again id is auto-genearated.
cabinet_name = models.CharField(max_length=100)
cabinet_size = models.IntegerField()
products = models.ManytoManyField(Product)#This automatically maps product_id n cabinet_id.
And your query would be.
x = Cabinet.objects.filter(product.id=some_value)
print (x.id , x.cabinet_name, x.cabinet_size) # I used print, but you can use it anyway you want.
This would be what you require. Please use the second solution if you are looking into something serious.

Related

fetching values from two tables based on each table having different conditions in django ORM

i have 2 models test1 and test2.
i want to query status condition from test1 and progress condition in test2 .
class test1:
iID = models.AutoField(primary_key=True)
iEID = models.BigIntegerField(_("EID"),default=0)
istatus = models.BooleanField(_("Status"),default=0)
class test2:
iid = models.AutoField(primary_key=True)
iEID = models.BigIntegerField(_("EID"),default=0)
progress = models.IntegerField(_("pgs"),blank=True,null=True)
i want query something like progess > 7 in test2 model and istatus = 1 in test1 model and common field for both tables is iEID
You can do it this way.
test1_list = test1.objects.filter(istatus=1).values_list('id','iEID')
test2_queryset = test2.objects.filter(progress__gt=7, iEID__in=[y for x, y in test1_list] )
test1_queryset = test1.objects.filter( iEID__in=test2_queryset.values_list('iEID') , id__in = [x for x, y in test1_list])
Now test1_queryset and test2_queryset will be having the objects whose progess > 7 , istatus = 1 and common iEID

Modify prefetched objects

Is it possible to modify prefetched objects without using save()?
class First(models.Model):
field = models.IntegerField()
class Second(models.Model):
first = models.ForeignKey(First, related_name='seconds')
some = models.IntegerField()
qs = First.objects.filter(field=12).prefetch_related('seconds')
qs[0].seconds.all()[0].some = 999
qs[0].seconds.all()[0] == 999 # should be True
UPDATE:
I found what was wrong. First need evaluate queryset e.g. len(qs) after filter.
I want to alter my question slightly. Can i modify foreign key relationship without hitting db?
qs = First.objects.filter(field=12).prefetch_related('seconds')
len(qs)
print(len(qs[0].seconds.all())) # output: 5
qs[0].seconds.all()[0].first_id = 2
print(len(qs[0].seconds.all())) # output: 4
Instead of doing
f.seconds.all()[0].some = 999
f.seconds.all()[0] == 999 # should be True
Do this..
first_object = f.seconds.all()[0]
first_object.some = 999
first_object.some == 999 #true

Saving a model using the PK of a 2nd level related field in Django

I have the following models:
class A(models.Model):
pass # omitted for shortness
class B(models.Model):
pass
class AB(models.Model):
prop_a = models.ForeignKey('A')
prop_b = models.ForeignKey('B')
class X(models.Model):
prop_ab = models.ForeignKey('AB')
I want to save a model of instance X, but without doing ab = AB.objects.get(prop_a=1, prop_b=2) and then x.prop_ab = ab.
I want something like this (assuming that all the proper entries in A, B and AB already exist):
x = X()
x.prop_ab__prop_a__id = 1
x.prop_ab__prop_b__id = 2
x.save()
Is something like this possible? (the above syntax doesn't work, I've tried)
assuming that all the proper entries in A, B and AB already exist
you can do this:
x = X()
x.prop_ab.prop_a_id = 1
x.prop_ab.prop_b_id = 2
x.save()
I need to do a bunch of save() of the X model in a foreach loop, so I also need to get the respective AB entries in that foreach. I'd like to minimize the number of queries I do through eliminating the get on AB
for x in X.objects.select_related('prop_ab'):
x.prop_ab.prop_a_id = 1
x.prop_ab.prop_b_id = 2
x.save()

Filtering over a list of date ranges in one ORM call

I am having the following structure:
class Player(models.Model):
name = models.CharField(max_length=50)
dob = models.DateField(max_length=80)
class Game(models.Model):
name = models.CharField(max_length=50)
class Attempts(models.Model):
player = models.ForeignKey("Player")
game = models.ForeignKey("Game")
won = models.BooleanField()
The class Attempts logs the attempts of each player and whether he has won or lost a game.Now I want to get number of people attempting a particular game in agr groups.For example people aged 0-18 have attempted a game 5 times and so on.I have consulted the following this post in django users and made the following code:
ranges = [(0,18),(18,25),(25,50)]
now = datetime.now()
groups = {}
for (a,b) in ranges:
# print str(a) + " " +str(b)
newer_date = (now - relativedelta(years=a)).date()
older_date = (now - relativedelta(years=b)).date()
print str(newer_date)
print str(older_date)
groups[str(a)+","+str(b)] = Attempts.objects.filter(game__pk = "101",player__dob__range=(older_date,newer_date)).count()
This also gives result correctly as:
{"0,18": 2, "25,50": 1, "18,25": 1}
How ever the queries made by this code are equal to number of categories in the ranges.I want to some how get this data in one single ORM query.Is it possible to do so ?

Django query using filters

I have 3 models in django:
class Movie(models.Model):
mid = models.IntegerField(primary_key = True)
name = models.CharField(max_length = 100)
class User(models.Model):
username = models.CharField(max_length=128, null=True)
uid = models.CharField(max_length=100)
movie = models.ManyToManyField(Movie, through = "Vote")
class Vote(models.Model):
movie = models.ForeignKey(Movie)
user = models.ForeignKey(User)
rating = models.IntegerField()
here rating = 0/1, 0 means dislike, 1 means like
i want to make some queries using filters:
find out all movies that a current user likes. For that i use this following 2 queries, but none of them work. In both cases it gives erroneous results
ans = Movie.objects.filter(vote__user = self).filter(vote__rating = 1)
ans = Movie.objects.filter(user__uid = self.uid).filter(vote__rating = 1)
I have a list of users in an array ids. I want to find out how many users from this list like a particular movie?
i tried this, but this is also incorrect:
ret = User.objects.filter(uid__in = ids).filter(vote__movie = mov).filter(vote__rating = 1)
can somebody please help me with these 2 queries?
I'd also suggest letting django assign the model's id's but if you are using a legacy database or for some other reason need to assign the id's you can query like so:
# uid is some uid
user = User.objects.get(uid=uid)
likes = Movie.objects.filter(vote__user=user, vote__rating=1)
or
likes = Movie.objects.filter(vote__user__uid=some_uid, vote__rating=1)
count of people in the list of users who like a specific movie:
>>> uids = ['1','2','3']
>>> # if mov is a Movie instance
>>> votes = Vote.objects.filter(user__uid__in=uids, movie=mov, rating=1)
>>> print votes.query
SELECT "so1_vote"."id", "so1_vote"."movie_id", "so1_vote"."user_id", "so1_vote"."rating" FROM "so1_vote" INNER JOIN "so1_user" ON ("so1_vote"."user_id" = "so1_user"."id") WHERE ("so1_user"."uid" IN (1, 2, 3) AND "so1_vote"."movie_id" = 1 AND "so1_vote"."rating" = 1 )
>>> # if mov is a mid for a movie
>>> # get movie instance by using Movie.objects.get(mid=mov)
>>> # or query:
>>> # votes = Vote.objects.filter(user__uid__in=uids, movie__mid=mov, rating=1)
>>> likes_count = votes.count()
>>> print likes_count
0
combined:
likes_count = Votes.objects.filter(user__uid__in=uids, movie=mov, rating=1).count()