Skip to content

Instantly share code, notes, and snippets.

@sassanh
Last active February 25, 2024 09:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sassanh/43ef664872c322a5f88434f10c5ce4ea to your computer and use it in GitHub Desktop.
Save sassanh/43ef664872c322a5f88434f10c5ce4ea to your computer and use it in GitHub Desktop.
Yes I was frustrated at the time, you're right about that. But I never asked a open source contributor to do it just cause I need it.
I invite all open source contributors working on this project to open google and search "left outer join django" they see lots of
discussion about it, then try "left join django" they see lots of other questions about same thing, then try "join django without
foreign key" and they'll see lots of OTHER questions about this same issue, then try whatever random query they can think of that's
related to this issue. The interesting thing is that while I was doing this from "1am" to "7am" I was able to find queries that
brought me 10 new unvisited results in first page of google search that were totally relevant to issue, can you imagine it:
6 hours of searching and after 6 hours still 10 unvisited relevant pages on first page of a google search. So lets instead of
ignoring this issue by labeling the issue reporter as selfish, don't be selfish and solve the issue of lots of people who are
struggling with this issue over past 10 years once for ever.
@thesealednectar22
Copy link

Hi, have you been able to find a workaround for that left outer join issue?

@sassanh
Copy link
Author

sassanh commented Feb 25, 2024

It's been 6 years and that project is not active anymore, but I found it in my archives and review the relevant parts, this is what I found:

            sub_sql = sub_queryset.query.sql_with_params()
            sql = (
                re.sub(
                    ' WHERE ',
                    ' LEFT OUTER JOIN ({}) AS "order_query"\
                    ON ("report_data"."id"="order_query"."id") WHERE '.format(
                        sub_sql[0] % tuple('\'{}\''.format(i) if i else i
                                           for i in sub_sql[1]),
                    ),
                    sql[0],
                ),
                sql[1],
            )
            sql = (
                re.sub(
                    '(ORDER BY ' + '[^,]*,' * order_index + ')',
                    '\\1 MIN("order_query"."value") {},'.format(
                        'DESC' if order_items[0] == '-' else 'ASC',
                    ),
                    sql[0] + ',',
                )[:-1],
                sql[1],
            )
            queryset = Data.objects.raw(*sql)

            queryset.__class__ = type(
                type(queryset).__name__,
                (type(queryset),),
                {'__len__': lambda self: count},
            )

So the idea is to get the SQL command from Django, modify it, run it with objects.raw and then inject __len__ method into its type. I don't remember the details and can't run the code to see how exactly it works, but as far as I remember I did inject __len__ so the generated queryset works better with Django Rest framework.

@thesealednectar22
Copy link

I tried doing
queryset.class = type(
type(queryset).name,
(type(queryset),),
{'len': lambda self: count},
)

after doing a Models.objects.raw(sql).
But it threw an error when passed to PageNumberPagination

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment