Count and group by foreign key and return model django











up vote
1
down vote

favorite












Data Model:




  • Each Library has many Books

  • Each Book may or may not be read by a User dictated by the UserBookReceipt


Objective:



Given a user, order the libraries by how many books they have read at each library.



Example:



User 1 has read:




  • 2 Books from Library 1

  • 5 Books from Library 2

  • 1 Book from Library 3

  • 0 Books from Library 4


We should return the libraries in order of number of books read by User 1 ie:



Library 2, Library 1, Library 3


Current solution



libraries = (UserBookReceipt.objects
.filter(user=user)
.values('book__library')
.annotate(rcount=Count('book__library'))
.order_by('-rcount')
)


Actual output



[
{'book_library': 2, 'rcount': 5},
{'book_library': 1, 'rcount': 2},
{'book_library': 3, 'rcount': 1}
]


Expected output



[
{'book_library': <Library: 2>, 'rcount': 5},
{'book_library': <Library: 1>, 'rcount': 2},
{'book_library': <Library: 3>, 'rcount': 1}
]


The actual output is 90% of what I want, except I want the book_library value to be instances of the django Library model rather than just the library id. Otherwise, I have to make another query to retrieve the Library objects which would probably require some inefficient ids__in query.



How can I count and group by the UserBookReceipt.book__library and return the Library model?



If I were to do this in SQL the query would look like



with rcount_per_lib as (
select lib.id, count(*) as rcount
from lib, books, user_book_receipts
where user_book_receipts.book_id = books.id
and lib.id = books.lib_id
and user_book_receipts.user_id = 1
group by lib.id)
select lib.*, rcount from rcount_per_lib
where lib.id = rcount_per_lib.id
order by rcount









share|improve this question




















  • 3




    If you are going to use SQL, you should really to use proper, explicit, standard JOIN syntax.
    – Gordon Linoff
    Nov 17 at 14:30






  • 1




    Why? AFAIK the and syntax is equivalent performance wise to INNER JOIN
    – david_adler
    Nov 17 at 14:36















up vote
1
down vote

favorite












Data Model:




  • Each Library has many Books

  • Each Book may or may not be read by a User dictated by the UserBookReceipt


Objective:



Given a user, order the libraries by how many books they have read at each library.



Example:



User 1 has read:




  • 2 Books from Library 1

  • 5 Books from Library 2

  • 1 Book from Library 3

  • 0 Books from Library 4


We should return the libraries in order of number of books read by User 1 ie:



Library 2, Library 1, Library 3


Current solution



libraries = (UserBookReceipt.objects
.filter(user=user)
.values('book__library')
.annotate(rcount=Count('book__library'))
.order_by('-rcount')
)


Actual output



[
{'book_library': 2, 'rcount': 5},
{'book_library': 1, 'rcount': 2},
{'book_library': 3, 'rcount': 1}
]


Expected output



[
{'book_library': <Library: 2>, 'rcount': 5},
{'book_library': <Library: 1>, 'rcount': 2},
{'book_library': <Library: 3>, 'rcount': 1}
]


The actual output is 90% of what I want, except I want the book_library value to be instances of the django Library model rather than just the library id. Otherwise, I have to make another query to retrieve the Library objects which would probably require some inefficient ids__in query.



How can I count and group by the UserBookReceipt.book__library and return the Library model?



If I were to do this in SQL the query would look like



with rcount_per_lib as (
select lib.id, count(*) as rcount
from lib, books, user_book_receipts
where user_book_receipts.book_id = books.id
and lib.id = books.lib_id
and user_book_receipts.user_id = 1
group by lib.id)
select lib.*, rcount from rcount_per_lib
where lib.id = rcount_per_lib.id
order by rcount









share|improve this question




















  • 3




    If you are going to use SQL, you should really to use proper, explicit, standard JOIN syntax.
    – Gordon Linoff
    Nov 17 at 14:30






  • 1




    Why? AFAIK the and syntax is equivalent performance wise to INNER JOIN
    – david_adler
    Nov 17 at 14:36













up vote
1
down vote

favorite









up vote
1
down vote

favorite











Data Model:




  • Each Library has many Books

  • Each Book may or may not be read by a User dictated by the UserBookReceipt


Objective:



Given a user, order the libraries by how many books they have read at each library.



Example:



User 1 has read:




  • 2 Books from Library 1

  • 5 Books from Library 2

  • 1 Book from Library 3

  • 0 Books from Library 4


We should return the libraries in order of number of books read by User 1 ie:



Library 2, Library 1, Library 3


Current solution



libraries = (UserBookReceipt.objects
.filter(user=user)
.values('book__library')
.annotate(rcount=Count('book__library'))
.order_by('-rcount')
)


Actual output



[
{'book_library': 2, 'rcount': 5},
{'book_library': 1, 'rcount': 2},
{'book_library': 3, 'rcount': 1}
]


Expected output



[
{'book_library': <Library: 2>, 'rcount': 5},
{'book_library': <Library: 1>, 'rcount': 2},
{'book_library': <Library: 3>, 'rcount': 1}
]


The actual output is 90% of what I want, except I want the book_library value to be instances of the django Library model rather than just the library id. Otherwise, I have to make another query to retrieve the Library objects which would probably require some inefficient ids__in query.



How can I count and group by the UserBookReceipt.book__library and return the Library model?



If I were to do this in SQL the query would look like



with rcount_per_lib as (
select lib.id, count(*) as rcount
from lib, books, user_book_receipts
where user_book_receipts.book_id = books.id
and lib.id = books.lib_id
and user_book_receipts.user_id = 1
group by lib.id)
select lib.*, rcount from rcount_per_lib
where lib.id = rcount_per_lib.id
order by rcount









share|improve this question















Data Model:




  • Each Library has many Books

  • Each Book may or may not be read by a User dictated by the UserBookReceipt


Objective:



Given a user, order the libraries by how many books they have read at each library.



Example:



User 1 has read:




  • 2 Books from Library 1

  • 5 Books from Library 2

  • 1 Book from Library 3

  • 0 Books from Library 4


We should return the libraries in order of number of books read by User 1 ie:



Library 2, Library 1, Library 3


Current solution



libraries = (UserBookReceipt.objects
.filter(user=user)
.values('book__library')
.annotate(rcount=Count('book__library'))
.order_by('-rcount')
)


Actual output



[
{'book_library': 2, 'rcount': 5},
{'book_library': 1, 'rcount': 2},
{'book_library': 3, 'rcount': 1}
]


Expected output



[
{'book_library': <Library: 2>, 'rcount': 5},
{'book_library': <Library: 1>, 'rcount': 2},
{'book_library': <Library: 3>, 'rcount': 1}
]


The actual output is 90% of what I want, except I want the book_library value to be instances of the django Library model rather than just the library id. Otherwise, I have to make another query to retrieve the Library objects which would probably require some inefficient ids__in query.



How can I count and group by the UserBookReceipt.book__library and return the Library model?



If I were to do this in SQL the query would look like



with rcount_per_lib as (
select lib.id, count(*) as rcount
from lib, books, user_book_receipts
where user_book_receipts.book_id = books.id
and lib.id = books.lib_id
and user_book_receipts.user_id = 1
group by lib.id)
select lib.*, rcount from rcount_per_lib
where lib.id = rcount_per_lib.id
order by rcount






python sql django postgresql






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 17 at 15:31

























asked Nov 17 at 14:29









david_adler

2,18722045




2,18722045








  • 3




    If you are going to use SQL, you should really to use proper, explicit, standard JOIN syntax.
    – Gordon Linoff
    Nov 17 at 14:30






  • 1




    Why? AFAIK the and syntax is equivalent performance wise to INNER JOIN
    – david_adler
    Nov 17 at 14:36














  • 3




    If you are going to use SQL, you should really to use proper, explicit, standard JOIN syntax.
    – Gordon Linoff
    Nov 17 at 14:30






  • 1




    Why? AFAIK the and syntax is equivalent performance wise to INNER JOIN
    – david_adler
    Nov 17 at 14:36








3




3




If you are going to use SQL, you should really to use proper, explicit, standard JOIN syntax.
– Gordon Linoff
Nov 17 at 14:30




If you are going to use SQL, you should really to use proper, explicit, standard JOIN syntax.
– Gordon Linoff
Nov 17 at 14:30




1




1




Why? AFAIK the and syntax is equivalent performance wise to INNER JOIN
– david_adler
Nov 17 at 14:36




Why? AFAIK the and syntax is equivalent performance wise to INNER JOIN
– david_adler
Nov 17 at 14:36












1 Answer
1






active

oldest

votes

















up vote
2
down vote



accepted










You need to change how you approach the queryset. Use Library rather than UserBookReceipt.



libraries = (Library.objects
.filter(book__userbookreceipt__user=user)
.annotate(rcount=Count('book__userbookreceipt', distinct=True))
.order_by('-rcount')
)
[x.rcount for x in libraries]





share|improve this answer























    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














     

    draft saved


    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53352158%2fcount-and-group-by-foreign-key-and-return-model-django%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    2
    down vote



    accepted










    You need to change how you approach the queryset. Use Library rather than UserBookReceipt.



    libraries = (Library.objects
    .filter(book__userbookreceipt__user=user)
    .annotate(rcount=Count('book__userbookreceipt', distinct=True))
    .order_by('-rcount')
    )
    [x.rcount for x in libraries]





    share|improve this answer



























      up vote
      2
      down vote



      accepted










      You need to change how you approach the queryset. Use Library rather than UserBookReceipt.



      libraries = (Library.objects
      .filter(book__userbookreceipt__user=user)
      .annotate(rcount=Count('book__userbookreceipt', distinct=True))
      .order_by('-rcount')
      )
      [x.rcount for x in libraries]





      share|improve this answer

























        up vote
        2
        down vote



        accepted







        up vote
        2
        down vote



        accepted






        You need to change how you approach the queryset. Use Library rather than UserBookReceipt.



        libraries = (Library.objects
        .filter(book__userbookreceipt__user=user)
        .annotate(rcount=Count('book__userbookreceipt', distinct=True))
        .order_by('-rcount')
        )
        [x.rcount for x in libraries]





        share|improve this answer














        You need to change how you approach the queryset. Use Library rather than UserBookReceipt.



        libraries = (Library.objects
        .filter(book__userbookreceipt__user=user)
        .annotate(rcount=Count('book__userbookreceipt', distinct=True))
        .order_by('-rcount')
        )
        [x.rcount for x in libraries]






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited 2 days ago









        david_adler

        2,18722045




        2,18722045










        answered Nov 17 at 15:51









        schillingt

        4,88211620




        4,88211620






























             

            draft saved


            draft discarded



















































             


            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53352158%2fcount-and-group-by-foreign-key-and-return-model-django%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Create new schema in PostgreSQL using DBeaver

            Deepest pit of an array with Javascript: test on Codility

            Fotorealismo