Django left join models - python

I want to left join the below tables and add a filter condition on approved_coupon field.
My models
class Voucher(models.Model):
voucher_id = models.UUIDField(default=uuid.uuid4, editable=False)
voucher_code = models.CharField()
class ApprovedCouponLine(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
approved_coupon = models.ForeignKey(ApprovedCoupon, on_delete=models.CASCADE, related_name='approved_coupon_lines')
coupon_code = models.ForeignKey(Voucher, on_delete=models.CASCADE, related_name='approved_coupon_lines_coupons')
I tried this, but it shows the inner join.
queryset = Voucher.objects.filter(approved_coupon_lines_coupons__approved_coupon_id='CD5FC4FE').values_list('code', flat=True)
Current Query:
SELECT "voucher_voucher"."code", "voucher_approvedcouponline"."id"
FROM "voucher_voucher"
INNER JOIN "voucher_approvedcouponline" ON ("voucher_voucher"."id" = "voucher_approvedcouponline"."coupon_code_id")
WHERE "voucher_approvedcouponline"."approved_coupon_id" = 'CD5FC4FE'
Expected Query:
SELECT "voucher_voucher"."code", "voucher_approvedcouponline"."id"
FROM "voucher_voucher"
LEFT JOIN "voucher_approvedcouponline" ON ("voucher_voucher"."id" = "voucher_approvedcouponline"."coupon_code_id" AND
"voucher_approvedcouponline"."approved_coupon_id" = 'CD5FC4FE'
)
What I missed in the above example?

Related

How to inner join 4 tables in Django?

We want to retrieve all table records at a time how to implement like SQL queries in django orm.
Example SQL query:
select *
from Company_info
inner join Bank_info on Bank_info.manufacturer = Company_info.manufacturer
inner join Company_info on Company_info.manufacturer = Company_info.manufacturer
inner join Transport_info on Transport_info.manufacturer = Company_info.manufacturer
Code:
class Manufacturer(models.Model):
name = models.CharField(max_length=42)
class Bank_info(models.Model):
account = models.CharField(max_length=42)
manufacturer = models.ForeignKey(Manufacturer, on_delete= models.CASCADE)
class Company_info(models.Model):
name= models.CharField(max_length=42)
manufacturer = models.ForeignKey(Manufacturer, on_delete= models.CASCADE)
class Transport_info(models.Model):
name= models.CharField(max_length=42)
manufacturer = models.ForeignKey(Manufacturer, on_delete= models.CASCADE)
You can use prefetch_related for this, as mentioned in comments:
Manufacturer.objects.all().prefetch_related('related_name2', 'related_name3', 'related_name4')
This, in fact, will not perform an SQL INNER JOIN, but will join prefetched objects on Python level - this will decrease hits to DB when using related object fields.

django 1.11.x -> 2.x migration. I got the incorrect 'group by' fields

I just upgraded the Django version. The model or code has not been modified in my app.
But... I get different results QuerySet.
Fields specified in 'Group by' are different when printing a 'query'.
Model:
class Content(models.Model):
id_field = models.AutoField(db_column='id_', primary_key=True)
...
collections = models.ManyToManyField('Collection',
through='CollectionMap',
through_fields=('contentid', 'collectionid'))
class CollectionMap(models.Model):
field_index = models.AutoField(db_column='_index', primary_key=True)
collectionid = models.ForeignKey(Collection, on_delete=models.CASCADE, db_column='collectionid')
contentid = models.ForeignKey(Content, on_delete=models.CASCADE, db_column='contentid')
field_time = models.DateTimeField(db_column='_time')
class Collection(models.Model):
field_index = models.AutoField(db_column='_index', primary_key=True)
name = models.CharField(unique=True, max_length=50)
collectionorder = models.IntegerField(db_column='collectionOrder', blank=True, null=True)
active = models.IntegerField(blank=True, null=True)
field_time = models.DateTimeField(db_column='_time')
Code:
Content.objects\
.annotate(count=Count('id_field')\
.values('id_field', 'collections__name')
Query:
1.11.X
SELECT
Content.id_, Collection. name
FROM Content
LEFT OUTER JOIN Collection_Map ON (Content.id_ = Collection_Map.contentid)
LEFT OUTER JOIN Collection ON (Collection_Map.collectionid = Collection._index)
GROUP BY Content.id_
ORDER BY Content.itemOrder DESC
LIMIT 50;
2.X
SELECT
Content.id_, Collection. name
FROM Content
LEFT OUTER JOIN Collection_Map ON (Content.id_ = Collection_Map.contentid)
LEFT OUTER JOIN Collection ON (Collection_Map.collectionid = Collection._index)
GROUP BY Content.id_, Collection. name
ORDER BY Content.itemOrder DESC
LIMIT 50;
Group By fields:
Version 1.11.X : GROUP BY Content.id
Version 2.X : GROUP BY Content.id, Collection.Name
I want this... '... GROUP BY Content.id ...'
What should I do??

django left outer join with condition

how to put condition in left outer join query in django.I have given sample query in below.
I need equivalent django query for below sql query.
Table 1
class LeadGroups(Audit):
user = models.ForeignKey(User)
group_name = models.CharField(max_length=250)
Table 2
class lead(Audit):
group = models.ForeignKey(LeadGroups, null='true', blank='true')
First_Name = models.CharField(max_length=255, null='true', blank='true')
Last_Name = models.CharField(max_length=255, null='true', blank='true')
Required query
SELECT "lead_leadgroups"."id", "lead_leadgroups"."created_by_id", "lead_leadgroups"."modified_by_id", "lead_leadgroups"."created_at", "lead_leadgroups"."modified_at", "lead_leadgroups"."customer_id", "lead_leadgroups"."user_id", "lead_leadgroups"."group_name", COUNT("lead_lead"."id") AS "totlacontact" FROM "lead_leadgroups"
LEFT OUTER JOIN "lead_lead" ON ( "lead_leadgroups"."id" = "lead_lead"."group_id" and **"lead_lead"."data_value" = True**)
WHERE ("lead_leadgroups"."customer_id" = 309 ) GROUP BY "lead_leadgroups"."id", "lead_leadgroups"."created_by_id", "lead_leadgroups"."modified_by_id", "lead_leadgroups"."created_at", "lead_leadgroups"."modified_at", "lead_leadgroups"."customer_id", "lead_leadgroups"."user_id", "lead_leadgroups"."group_name"
ORDER BY "lead_leadgroups"."id" ASC LIMIT 100

Erroneous group_by query generated in python django

I am using Django==1.8.7 and I have the following models
# a model in users.py
class User(models.Model):
id = models.AutoField(primary_key=True)
username = models.CharField(max_length=100, blank=True)
displayname = models.CharField(max_length=100, blank=True)
# other fields deleted
# a model in healthrepo.py
class Report(models.Model):
id = models.AutoField(primary_key=True)
uploaded_by = models.ForeignKey(User, related_name='uploads',
db_index=True)
owner = models.ForeignKey(User, related_name='reports', db_index=True)
# other fields like dateofreport, deleted
I use the following Django queryset:
Report.objects.filter(owner__id=1).values('uploaded_by__username',
'uploaded_by__displayname').annotate(
total=Count('uploaded_by__username')
)
I see that this generates the following query:
SELECT T3."username", T3."displayname", COUNT(T3."username") AS "total" FROM "healthrepo_report"
INNER JOIN "users_user" T3 ON ( "healthrepo_report"."uploaded_by_id" = T3."id" )
WHERE "healthrepo_report”.”owner_id" = 1
GROUP BY T3."username", T3."displayname", "healthrepo_report"."dateofreport", "healthrepo_report”.”owner_id", "healthrepo_report"."uploaded_by_id"
ORDER BY "healthrepo_report"."dateofreport" DESC, "healthrepo_report"."user_id" ASC, "healthrepo_report"."uploaded_by_id" ASC
However, what I really wanted was just grouping based on "healthrepo_report”.”owner_id" and not multiple fields. i.e. What I wanted was:
SELECT T3."username", T3."displayname", COUNT(T3."username") AS "total" FROM "healthrepo_report"
INNER JOIN "users_user" T3 ON ( "healthrepo_report"."uploaded_by_id" = T3."id" )
WHERE "healthrepo_report”.”owner_id" = 1
GROUP BY T3."username", T3."displayname" ORDER BY "healthrepo_report"."dateofreport" DESC, "healthrepo_report"."user_id" ASC, "healthrepo_report"."uploaded_by_id" ASC
I am wondering why this is happening and how do I get grouping based on single column.
I just saw this post:
Django annotate and values(): extra field in 'group by' causes unexpected results
Changing the query by adding empty order_by() fixes it
Report.objects.filter(owner__id=1).values('uploaded_by__username',
'uploaded_by__displayname').annotate(
total=Count('uploaded_by__username')
).order_by()

Django - How define field name for reverse related model in select_related

So, i have this models:
class Channel(models.Model):
name = models.CharField(max_length=255, db_index=True)
descr = models.TextField(blank=True)
start = models.DateTimeField()
end = models.DateTimeField()
external_id = models.CharField(blank=True, max_length=64,db_index=True)
class Programm(models.Model):
channel = models.ForeignKey(Channel)
name = models.CharField(max_length=255, db_index=True)
descr = models.TextField(blank=True)
start = models.DateTimeField()
end = models.DateTimeField()
is_live = models.BooleanField(default=False, db_index=True)
class Guide(models.Model):
programm = models.ForeignKey(Programm)
name = models.CharField(max_length=255, db_index=True)
descr = models.TextField(blank=True)
start_date = models.DateField(db_index=True)
start_time = models.TimeField(db_index=True)
duration = models.TimeField(blank=True)
When i need build list of tv shows for one channel:
Guide.objects.select_related().filter(programm__channel=channel,
start_date__lte=timezone.now().date()+timezone.timedelta(days=7),
start_date__gte=timezone.now().date()-timezone.timedelta(days=1))
Django performs such query:
SELECT `tvguide_guide`.`id`,
`tvguide_guide`.`programm_id`,
/*here all fields from all tables */
FROM `tvguide_guide`
INNER JOIN `tvguide_programm` ON
(`tvguide_guide`.`programm_id` = `tvguide_programm`.`id`)
INNER JOIN `tvguide_channel` ON
(`tvguide_programm`.`channel_id` = `tvguide_channel`.`id`)
WHERE (`tvguide_programm`.`channel_id` = 1 AND
`tvguide_guide`.`start_date` >= '2014-01-16' AND
`tvguide_guide`.`start_date` <= '2014-01-24' )
ORDER BY `tvguide_guide`.`start_date` ASC, `tvguide_guide`.`start_time` ASC
Django documentation says:
You can also refer to the reverse direction of a OneToOneField in the
list of fields passed to select_related — that is, you can traverse a
OneToOneField back to the object on which the field is defined.
Instead of specifying the field name, use the related_name for the
field on the related object.
So... How it should look??? I can not figure out =( Set an example, please.
In the end, I have a SQL query that would look like this:
SELECT `tvguide_guide`.`name`,
`tvguide_guide`.`descr`,
`tvguide_guide`.`start_date`,
`tvguide_guide`.`start_time`,
`tvguide_programm`.`name`,
`tvguide_channel`.`name` FROM ...
You don't have to do anything special for that. Just refer to the class variables directly:
guides = Guide.objects.select_related("programm", "programm__channel").filter(programm__channel=channel,
start_date__lte=timezone.now().date()+timezone.timedelta(days=7),
start_date__gte=timezone.now().date()-timezone.timedelta(days=1))
programms = [guide.programm for guide in guides]
channels = [programm.channel for programm in programms]
Notice that select_related is modified to cache the values in the query.

Categories

Resources