#29262: Custom Left Outer Join in Queries
-------------------------------------+-------------------------------------
     Reporter:  Sassan Haradji       |                    Owner:  nobody
         Type:  New feature          |                   Status:  new
    Component:  Database layer       |                  Version:
  (models, ORM)                      |
     Severity:  Normal               |               Resolution:
     Keywords:  ORM Join             |             Triage Stage:  Accepted
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  0
-------------------------------------+-------------------------------------

Comment (by Alexandr Artemyev):

 I believe my case relates to this issue.

 I have a user model and a second model like this

 {{{
 class SecondModel(models.Model):
     date = models.DateField()
     from_member = models.ForeignKey(User, models.CASCADE, '+',)
     to_member = models.ForeignKey(User, models.CASCADE, '+')
     first_value = models.IntegerField(default=0)
     second_value = models.IntegerField(default=0)
 }}}


 I want to left join this subquery with the User model on `id=target`:
 {{{
 subquery = (
     SecondModel.objects.filter(
         Q(from_member=self.user) | Q(to_member=self.user),
         date__gte=start_date, date__lte=end_date,
     ).annotate(
         target=Case(When(Q(from_member=self.user),
 then=F('to_member_id')), default=F('from_member_id')),
     ).values('target').annotate(
         sum_first_value=Sum('first_value'),
         sum_second_value=Sum('second_value'),
         total=F('sum_first_value') + F('sum_second_value'),
     )
 )
 }}}


 I imagine it somehow like this:

 {{{
 qs = User.objects.annotate(subquery=subquery)
 }}}
 After that filter/exclude/order_by features should work.
 Also I should have access to fields like
 qs[0].subquery_first_value/qs[0].subquery_second_value

 Here is an example SQL query that I want to be generated:
 {{{
 SELECT "users".*, "subquery".*
 FROM "users"
 LEFT OUTER JOIN
   (SELECT CASE
               WHEN "second_model"."from_member_id" = 7 THEN
 "second_model"."to_member_id"
               ELSE "second_model"."from_member_id"
           END AS "target",
           SUM("second_model"."first_value") AS "sum_first_value",
           SUM("second_model"."second_value") AS "sum_second_value",
    FROM "second_model"
    WHERE ("second_model"."from_member_id" = 7
           OR "second_model"."to_member_id" = 7) -- also the condition for
 date on start and end
    GROUP BY CASE
                 WHEN "second_model"."from_member_id" = 7 THEN
 "second_model"."to_member_id"
                 ELSE "second_model"."from_member_id"
             END) subquery ON ("users"."id" = subquery."target")
 WHERE "users"."id" = 502
 }}}

 I found a solution that resolves my problem:
 https://stackoverflow.com/a/42816689/5628843
 using CustomJoin helps me, but to access values i need to use extra, and
 this code doesn’t look very nice

 {{{
 join_to(Users, subquery, 'id', 'target', queryset, 'subquery').extra(
             select={
                 field_name: f'COALESCE({field_name}, 0)'
                 for field_name in (
                     'sum_first_value',
                     'sum_second_value',
                 )
             }
         )
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/29262#comment:14>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/065.8df639bc920e71c8e134507f1c929e83%40djangoproject.com.

Reply via email to