Join request in django between three tables and display all attributes - python

I have three models
class A(models.Model):
field1 = models.IntegerField()
class B(models.Model):
id_a = models.ForeignKey(A,on_delete=models.CASCADE)
field1 = models.IntegerField()
field2 = models.IntegerField()
class C(models.Model):
id_a = models.ForeignKey(A,on_delete=models.CASCADE)
field1 = models.IntegerField()
field2 = models.IntegerField()
I want to write a request that looks like this: SELECT * FROM B,C,A WHERE B.id_a=C.id_a WHERE A.id_a=2 and display all the attributes of the two tablesHere is what I tried to do:
a_id_att = 1
data = B.objects.filter(id_a=C.objects.filter(id_a=a_id_att)[0])
It does not work. How to write the join and make to display all the attributes of the tables?

The SQL statement that you wrote seems strange.
SELECT * FROM B, C, A
WHERE B.id_a = C.id_a
AND A.id_a = 2
It seems that you want a single row from A and then all related rows from B and C, which your SQL query does NOT achieve.
Did you mean something like this:
SELECT * FROM B, C, A
WHERE A.id = 2
AND B.id_a = A.id
AND C.id_a = A.id
You can achieve something like that in Django using prefetch_related(), which builds a query so that the related rows are also loaded into memory in the first query and not in subsequent queries.
# this will return a queryset with a single element, or empty
qs = A.objects.prefetch_related('b_set', 'c_set').filter(id=2)
for elem in qs: # here the single DB query is made
print(elem.field1) # A.field1
for det in elem.b_set.all():
print(det.field1) # B.field1, does NOT make another DB query
print(det.field2) # B.field2, does NOT make another DB query
for det in elem.c_set.all():
print(det.field1) # C.field1, does NOT make another DB query
print(det.field2) # C.field2, does NOT make another DB query
Note: I use b_set here because that is the default for the ForeignKey field; this changes if the field would specify a different related_name.
Does this address and solve your issue?

Related

how to convert sql query to django queryset?

i have two tables like categories and items in models items has foreign key of categories,here we have 4 categories and 12 items where each category has 3 items how to write a query set to get query set to get items with same category
i know how to write Sql query (select * from category where category_id =1;). how to write it in d'jango query set.
You can achieve it by using Django Queries:
Item.objects.filter(category__id=1)
As mentioned in the Kamil's answer, you could use filters or if you want to use SQL query as is, you could also use raw queries. An example (taken from official docs) -
class Person(models.Model):
first_name = models.CharField(...)
last_name = models.CharField(...)
birth_date = models.DateField(...)
And querying it would be -
# querying with SQL raw query
for p in Person.objects.raw('SELECT * FROM myapp_person'):
And in your case -
# assuming your query is correct
Item.objects.raw('select * from category where myapp_category_id = 1')

how to let django achieve inner join

there are two tables:
class TBLUserProfile(models.Model):
userid = models.IntegerField(primary_key=True)
relmusicuid = models.IntegerField()
fansnum = models.IntegerField()
class TSinger(models.Model):
fsinger_id = models.IntegerField()
ftbl_user_profile = models.ForeignKey(TBLUserProfile, db_column='Fsinger_id')
I want to get Tsinger info and then order by TBLUserProfile.fansnum, I know how to write sql query: select * from t_singer INNER JOIN tbl_user_profile ON (tbl_user_profile.relmusicuid=t_singer.Fsinger_id) order by tbl_user_profile.fansnum, but I don't want to use model raw function. relmusicuid is not primary key otherwise I can use ForeignKey to let it work. How can I use django model to achieve this?
You can do like this :
Tsinger.objects.all().order_by('ftbl_user_profile__fansnum')
For information about Django JOIN :
https://docs.djangoproject.com/en/1.8/topics/db/examples/many_to_one/

Joining Multiple Tables in Django

I have looked through around and there doesn't seem to be anything that has exactly answered what I am looking for, using the following model I want to join all the tables:
class A(models.Model):
name = models.CharField(max_length=60)
class B(models.Model):
a = models.ForeignField(A)
class C(models.Model):
a = models.ForeignField(A)
class D(models.Model):
a = models.ForeignField(A)
This is a very basic sort of structure I have going on, I want to join all the tables based on there foreign key link the A. I have looked at select_related but it seems like that is the reverse direction of what I want to do because it links an object to what it references and I want to join based on what references it.
Basically I want to join the tables like this MySQL query:
SELECT * FROM A, B, C, D WHERE A.id = B.aID AND A.id = C.aID AND A.id = D.aID;
You can use a custom join for your purpose:
# assume our models.py contains the following
class Contact(models.Model):
name = models.CharField(max_length=255)
phones = models.ManyToManyField('Phone')
addresses = models.ManyToManyField('Address')
class Phone(models.Model):
number = models.CharField(max_length=16)
# join as follows
contacts = Contact.objects.extra(
select={'phone': 'crm_phone.number'}
).order_by('name')
# setup intial FROM clause
# OR contacts.query.get_initial_alias()
contacts.query.join((None, 'crm_contact', None, None))
# join to crm_contact_phones
connection = (
'crm_contact',
'crm_contact_phones',
'id',
'contact_id',
)
contacts.query.join(connection, promote=True)
# join to crm_phone
connection = (
'crm_contact_phones',
'crm_phone',
'phone_id',
'id',
)
contacts.query.join(connection, promote=True)
Wash, rinse, repeat for every pair of tables till you're happy. If this is too involved, you can always use custom SQL.

how to retrive values form RawQuerySet in django?

my input query is
query = "select * from tab1 left join tab2 on tab2.patient_id =tab1.patient_id ,tab3 left join tab4 on tab4.patient_id =tab3.patient_id"
data = model_name.objects.raw(query)
How do you retrieve values from a RawQuerySet?
The result obtained by making raw queries using raw method of Manager generates instances similar to instances generated using get or filter method. To get a field simply do obj_name.attr.
For eg:
class Tab(models.Model):
field1 = models.BooleanField()
field2 = models.PositiveIntegerField()
query = "select * from app_name_tab"
objs = Tab.objects.raw(query)
for obj in objs:
print obj.field1, obj.field2
For more info, refer to https://docs.djangoproject.com/en/dev/topics/db/sql/

How can I do INNER JOIN in Django in legacy database?

Sorry for probably simple question but I'm a newby in Django and really confused.
I have an ugly legacy tables that I can not change.
It has 2 tables:
class Salespersons(models.Model):
id = models.IntegerField(unique=True, primary_key=True)
xsin = models.IntegerField()
name = models.CharField(max_length=200)
surname = models.CharField(max_length=200)
class Store(models.Model):
id = models.IntegerField(unique=True, primary_key=True)
xsin = models.IntegerField()
brand = models.CharField(max_length=200)
So I suppose I can not add Foreign keys in class definitions because they change the tables.
I need to execute such sql request:
SELECT * FROM Salespersons, Store INNER JOIN Store ON (Salespersons.xsin = Store.xsin);
How can I achieve it using Django ORM?
Or I'm allowed to get Salespersons and Store separately i.e.
stores = Store.objects.filter(xsin = 1000)
salespersons = Salespersons.objects.filter(xsin = 1000)
Given your example query, are your tables actually named Salespersons/Store?
Anyway, something like this should work:
results = Salespersons.objects.extra(tables=["Store"],
where=["""Salespersons.xsin = Store.xsin"""])
However, given the names of the tables/models it doesn't seem to me that an inner join would be logically correct. Unless you always have just 1 salesperson per store with same xsin.
If you can make one of the xsin fields unique, you can use a ForeignKey with to_field to generate the inner join like this:
class Salespersons(models.Model):
xsin = models.IntegerField(unique=True)
class Store(models.Model):
xsin = models.ForeignKey(Salespersons, db_column='xsin', to_field='xsin')
>>> Store.objects.selected_related('xsin')
I don't see why you can't use the models.ForeignKey fields even if the database lacks the constraints -- if you don't explicitly execute the SQL to change the database then the tables won't change. If you use a ForeignKey then you can use Salespersons.objects.select_related('xsin') to request that the related objects are fetched at the same time.

Categories