Django: select_related with multi table inheritance












1














I have the following model structure:



class A(models.Model):
prop_a = models.CharField(max_length=255)

class B(A):
prop_b = models.CharField(max_length=255)

class C(A):
prop_c = models.CharField(max_length=255)

class D(models.Model):
fk = models.ForeignKey('A')


So essentially, I have a model (D) which has a foreign key to an 'abstract' model (A) which is subclassed by B and C.



Now, when I run D.objects.all().select_related(), only the properties of Aare queried. I assume this is because at query time, Django does not know which child class the fk is an instance of (and neither do I in my current structure).



Is there any way to query the properties of the child class without changing the model structure?



I also tried prefetch_related and tried using an InheritanceManager from django-model-utils, both to no avail.



Edit: To clarify, I am looking for a way to iterate over objects of D, accessing the concrete values of fk (which are either B or C objects) while only hitting the database once.



Running D.objects.all().select_related() produces the query



'SELECT "mapping_d"."id", "mapping_d"."fk_id", "mapping_a"."id", "mapping_a"."prop_a" FROM "mapping_d" INNER JOIN "mapping_a" ON ("mapping_d"."fk_id" = "mapping_a"."id")'



Let's say one of those is an object d of type D whose property fk is of type C.



Now, when I access the value d.fk.c, Django runs an additional query to get the properties of C:



'SELECT "mapping_a"."id", "mapping_a"."prop_a", "mapping_c"."a_ptr_id", "mapping_c"."prop_c" FROM "mapping_c" INNER JOIN "mapping_a" ON ("mapping_c"."a_ptr_id" = "mapping_a"."id") WHERE "mapping_c"."a_ptr_id" = 3'



I want to avoid this additional query per object of D. Using an InheritanceManager in the proposed way does not seem to do that.










share|improve this question





























    1














    I have the following model structure:



    class A(models.Model):
    prop_a = models.CharField(max_length=255)

    class B(A):
    prop_b = models.CharField(max_length=255)

    class C(A):
    prop_c = models.CharField(max_length=255)

    class D(models.Model):
    fk = models.ForeignKey('A')


    So essentially, I have a model (D) which has a foreign key to an 'abstract' model (A) which is subclassed by B and C.



    Now, when I run D.objects.all().select_related(), only the properties of Aare queried. I assume this is because at query time, Django does not know which child class the fk is an instance of (and neither do I in my current structure).



    Is there any way to query the properties of the child class without changing the model structure?



    I also tried prefetch_related and tried using an InheritanceManager from django-model-utils, both to no avail.



    Edit: To clarify, I am looking for a way to iterate over objects of D, accessing the concrete values of fk (which are either B or C objects) while only hitting the database once.



    Running D.objects.all().select_related() produces the query



    'SELECT "mapping_d"."id", "mapping_d"."fk_id", "mapping_a"."id", "mapping_a"."prop_a" FROM "mapping_d" INNER JOIN "mapping_a" ON ("mapping_d"."fk_id" = "mapping_a"."id")'



    Let's say one of those is an object d of type D whose property fk is of type C.



    Now, when I access the value d.fk.c, Django runs an additional query to get the properties of C:



    'SELECT "mapping_a"."id", "mapping_a"."prop_a", "mapping_c"."a_ptr_id", "mapping_c"."prop_c" FROM "mapping_c" INNER JOIN "mapping_a" ON ("mapping_c"."a_ptr_id" = "mapping_a"."id") WHERE "mapping_c"."a_ptr_id" = 3'



    I want to avoid this additional query per object of D. Using an InheritanceManager in the proposed way does not seem to do that.










    share|improve this question



























      1












      1








      1







      I have the following model structure:



      class A(models.Model):
      prop_a = models.CharField(max_length=255)

      class B(A):
      prop_b = models.CharField(max_length=255)

      class C(A):
      prop_c = models.CharField(max_length=255)

      class D(models.Model):
      fk = models.ForeignKey('A')


      So essentially, I have a model (D) which has a foreign key to an 'abstract' model (A) which is subclassed by B and C.



      Now, when I run D.objects.all().select_related(), only the properties of Aare queried. I assume this is because at query time, Django does not know which child class the fk is an instance of (and neither do I in my current structure).



      Is there any way to query the properties of the child class without changing the model structure?



      I also tried prefetch_related and tried using an InheritanceManager from django-model-utils, both to no avail.



      Edit: To clarify, I am looking for a way to iterate over objects of D, accessing the concrete values of fk (which are either B or C objects) while only hitting the database once.



      Running D.objects.all().select_related() produces the query



      'SELECT "mapping_d"."id", "mapping_d"."fk_id", "mapping_a"."id", "mapping_a"."prop_a" FROM "mapping_d" INNER JOIN "mapping_a" ON ("mapping_d"."fk_id" = "mapping_a"."id")'



      Let's say one of those is an object d of type D whose property fk is of type C.



      Now, when I access the value d.fk.c, Django runs an additional query to get the properties of C:



      'SELECT "mapping_a"."id", "mapping_a"."prop_a", "mapping_c"."a_ptr_id", "mapping_c"."prop_c" FROM "mapping_c" INNER JOIN "mapping_a" ON ("mapping_c"."a_ptr_id" = "mapping_a"."id") WHERE "mapping_c"."a_ptr_id" = 3'



      I want to avoid this additional query per object of D. Using an InheritanceManager in the proposed way does not seem to do that.










      share|improve this question















      I have the following model structure:



      class A(models.Model):
      prop_a = models.CharField(max_length=255)

      class B(A):
      prop_b = models.CharField(max_length=255)

      class C(A):
      prop_c = models.CharField(max_length=255)

      class D(models.Model):
      fk = models.ForeignKey('A')


      So essentially, I have a model (D) which has a foreign key to an 'abstract' model (A) which is subclassed by B and C.



      Now, when I run D.objects.all().select_related(), only the properties of Aare queried. I assume this is because at query time, Django does not know which child class the fk is an instance of (and neither do I in my current structure).



      Is there any way to query the properties of the child class without changing the model structure?



      I also tried prefetch_related and tried using an InheritanceManager from django-model-utils, both to no avail.



      Edit: To clarify, I am looking for a way to iterate over objects of D, accessing the concrete values of fk (which are either B or C objects) while only hitting the database once.



      Running D.objects.all().select_related() produces the query



      'SELECT "mapping_d"."id", "mapping_d"."fk_id", "mapping_a"."id", "mapping_a"."prop_a" FROM "mapping_d" INNER JOIN "mapping_a" ON ("mapping_d"."fk_id" = "mapping_a"."id")'



      Let's say one of those is an object d of type D whose property fk is of type C.



      Now, when I access the value d.fk.c, Django runs an additional query to get the properties of C:



      'SELECT "mapping_a"."id", "mapping_a"."prop_a", "mapping_c"."a_ptr_id", "mapping_c"."prop_c" FROM "mapping_c" INNER JOIN "mapping_a" ON ("mapping_c"."a_ptr_id" = "mapping_a"."id") WHERE "mapping_c"."a_ptr_id" = 3'



      I want to avoid this additional query per object of D. Using an InheritanceManager in the proposed way does not seem to do that.







      python django inheritance






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 19 '18 at 13:56

























      asked Nov 16 '18 at 15:55









      Silvester

      31629




      31629
























          1 Answer
          1






          active

          oldest

          votes


















          2














          I use Inheritance Manager usualy and runs as expected.



          1) Remember to set the inheritance manager on A:



          class A(models.Model):
          # ...
          objects = InheritanceManager()


          2) Make the right query:



          some_d_object = D.objects.get( pk = 1 )
          related = some_d_object.fk.all().select_related()


          Noticte than, your query D.objects.all().select_related() will returns D objects. Nobody inherits from D, then, no subclasses, just D objects.



          3) Enjoy inheritance.



          Edited I edit this quetion becase the OP comment.




          With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once? –




          Ok, le'ts try to write an answer, because I really don't understand exactely witch objects OP is looking for. Question is fine because he has written almost a Minimal, Complete, and Verifiable example but I don't know expected values, Let's try with some samples.



          1) If you want all objects, as easy as:



          all_objects = A.objects.all().select_subclasses()


          2) If you want to filter, then, do it. I write a sample:



          filtered_objects = A.objects.filter( d__pk = 1 ).select_subclasses()


          3) Get all subclasses, and also, D class, in a single query:



          Unfortunatelly you can not apply prefetch_related (may be you can but I don't know how to do it). Then you need to massage data with itertools.



          all_objects_and_D = list(
          A
          .objects
          .select_related('D')
          .select_subclasses()
          .order_by( 'D__pk' )
          )
          #at this point use itertools to massage your data
          keyfunc = lambda x: x.D
          data = [ { k, list(g) }
          for k, g in
          itertools.groupby(all_objects_and_D, key=keyfunc )
          ]





          share|improve this answer























          • With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once?
            – Silvester
            Nov 19 '18 at 9:05










          • hi @Silvester, I have updated answer. Enjoy.
            – dani herrera
            Nov 19 '18 at 10:40










          • Thank you for taking the time. I think I left it a little bit unclear what exactly I am trying to do, I updated the question accordingly. Sorry for the confusion.
            – Silvester
            Nov 19 '18 at 13:56












          • @Silvester, my bad. I mixed select_subclasses and select_related. Now I have fix it. Sorry.
            – dani herrera
            Nov 19 '18 at 14:52











          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',
          autoActivateHeartbeat: false,
          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%2f53341329%2fdjango-select-related-with-multi-table-inheritance%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









          2














          I use Inheritance Manager usualy and runs as expected.



          1) Remember to set the inheritance manager on A:



          class A(models.Model):
          # ...
          objects = InheritanceManager()


          2) Make the right query:



          some_d_object = D.objects.get( pk = 1 )
          related = some_d_object.fk.all().select_related()


          Noticte than, your query D.objects.all().select_related() will returns D objects. Nobody inherits from D, then, no subclasses, just D objects.



          3) Enjoy inheritance.



          Edited I edit this quetion becase the OP comment.




          With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once? –




          Ok, le'ts try to write an answer, because I really don't understand exactely witch objects OP is looking for. Question is fine because he has written almost a Minimal, Complete, and Verifiable example but I don't know expected values, Let's try with some samples.



          1) If you want all objects, as easy as:



          all_objects = A.objects.all().select_subclasses()


          2) If you want to filter, then, do it. I write a sample:



          filtered_objects = A.objects.filter( d__pk = 1 ).select_subclasses()


          3) Get all subclasses, and also, D class, in a single query:



          Unfortunatelly you can not apply prefetch_related (may be you can but I don't know how to do it). Then you need to massage data with itertools.



          all_objects_and_D = list(
          A
          .objects
          .select_related('D')
          .select_subclasses()
          .order_by( 'D__pk' )
          )
          #at this point use itertools to massage your data
          keyfunc = lambda x: x.D
          data = [ { k, list(g) }
          for k, g in
          itertools.groupby(all_objects_and_D, key=keyfunc )
          ]





          share|improve this answer























          • With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once?
            – Silvester
            Nov 19 '18 at 9:05










          • hi @Silvester, I have updated answer. Enjoy.
            – dani herrera
            Nov 19 '18 at 10:40










          • Thank you for taking the time. I think I left it a little bit unclear what exactly I am trying to do, I updated the question accordingly. Sorry for the confusion.
            – Silvester
            Nov 19 '18 at 13:56












          • @Silvester, my bad. I mixed select_subclasses and select_related. Now I have fix it. Sorry.
            – dani herrera
            Nov 19 '18 at 14:52
















          2














          I use Inheritance Manager usualy and runs as expected.



          1) Remember to set the inheritance manager on A:



          class A(models.Model):
          # ...
          objects = InheritanceManager()


          2) Make the right query:



          some_d_object = D.objects.get( pk = 1 )
          related = some_d_object.fk.all().select_related()


          Noticte than, your query D.objects.all().select_related() will returns D objects. Nobody inherits from D, then, no subclasses, just D objects.



          3) Enjoy inheritance.



          Edited I edit this quetion becase the OP comment.




          With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once? –




          Ok, le'ts try to write an answer, because I really don't understand exactely witch objects OP is looking for. Question is fine because he has written almost a Minimal, Complete, and Verifiable example but I don't know expected values, Let's try with some samples.



          1) If you want all objects, as easy as:



          all_objects = A.objects.all().select_subclasses()


          2) If you want to filter, then, do it. I write a sample:



          filtered_objects = A.objects.filter( d__pk = 1 ).select_subclasses()


          3) Get all subclasses, and also, D class, in a single query:



          Unfortunatelly you can not apply prefetch_related (may be you can but I don't know how to do it). Then you need to massage data with itertools.



          all_objects_and_D = list(
          A
          .objects
          .select_related('D')
          .select_subclasses()
          .order_by( 'D__pk' )
          )
          #at this point use itertools to massage your data
          keyfunc = lambda x: x.D
          data = [ { k, list(g) }
          for k, g in
          itertools.groupby(all_objects_and_D, key=keyfunc )
          ]





          share|improve this answer























          • With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once?
            – Silvester
            Nov 19 '18 at 9:05










          • hi @Silvester, I have updated answer. Enjoy.
            – dani herrera
            Nov 19 '18 at 10:40










          • Thank you for taking the time. I think I left it a little bit unclear what exactly I am trying to do, I updated the question accordingly. Sorry for the confusion.
            – Silvester
            Nov 19 '18 at 13:56












          • @Silvester, my bad. I mixed select_subclasses and select_related. Now I have fix it. Sorry.
            – dani herrera
            Nov 19 '18 at 14:52














          2












          2








          2






          I use Inheritance Manager usualy and runs as expected.



          1) Remember to set the inheritance manager on A:



          class A(models.Model):
          # ...
          objects = InheritanceManager()


          2) Make the right query:



          some_d_object = D.objects.get( pk = 1 )
          related = some_d_object.fk.all().select_related()


          Noticte than, your query D.objects.all().select_related() will returns D objects. Nobody inherits from D, then, no subclasses, just D objects.



          3) Enjoy inheritance.



          Edited I edit this quetion becase the OP comment.




          With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once? –




          Ok, le'ts try to write an answer, because I really don't understand exactely witch objects OP is looking for. Question is fine because he has written almost a Minimal, Complete, and Verifiable example but I don't know expected values, Let's try with some samples.



          1) If you want all objects, as easy as:



          all_objects = A.objects.all().select_subclasses()


          2) If you want to filter, then, do it. I write a sample:



          filtered_objects = A.objects.filter( d__pk = 1 ).select_subclasses()


          3) Get all subclasses, and also, D class, in a single query:



          Unfortunatelly you can not apply prefetch_related (may be you can but I don't know how to do it). Then you need to massage data with itertools.



          all_objects_and_D = list(
          A
          .objects
          .select_related('D')
          .select_subclasses()
          .order_by( 'D__pk' )
          )
          #at this point use itertools to massage your data
          keyfunc = lambda x: x.D
          data = [ { k, list(g) }
          for k, g in
          itertools.groupby(all_objects_and_D, key=keyfunc )
          ]





          share|improve this answer














          I use Inheritance Manager usualy and runs as expected.



          1) Remember to set the inheritance manager on A:



          class A(models.Model):
          # ...
          objects = InheritanceManager()


          2) Make the right query:



          some_d_object = D.objects.get( pk = 1 )
          related = some_d_object.fk.all().select_related()


          Noticte than, your query D.objects.all().select_related() will returns D objects. Nobody inherits from D, then, no subclasses, just D objects.



          3) Enjoy inheritance.



          Edited I edit this quetion becase the OP comment.




          With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once? –




          Ok, le'ts try to write an answer, because I really don't understand exactely witch objects OP is looking for. Question is fine because he has written almost a Minimal, Complete, and Verifiable example but I don't know expected values, Let's try with some samples.



          1) If you want all objects, as easy as:



          all_objects = A.objects.all().select_subclasses()


          2) If you want to filter, then, do it. I write a sample:



          filtered_objects = A.objects.filter( d__pk = 1 ).select_subclasses()


          3) Get all subclasses, and also, D class, in a single query:



          Unfortunatelly you can not apply prefetch_related (may be you can but I don't know how to do it). Then you need to massage data with itertools.



          all_objects_and_D = list(
          A
          .objects
          .select_related('D')
          .select_subclasses()
          .order_by( 'D__pk' )
          )
          #at this point use itertools to massage your data
          keyfunc = lambda x: x.D
          data = [ { k, list(g) }
          for k, g in
          itertools.groupby(all_objects_and_D, key=keyfunc )
          ]






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 19 '18 at 14:51

























          answered Nov 16 '18 at 16:35









          dani herrera

          27.5k344107




          27.5k344107












          • With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once?
            – Silvester
            Nov 19 '18 at 9:05










          • hi @Silvester, I have updated answer. Enjoy.
            – dani herrera
            Nov 19 '18 at 10:40










          • Thank you for taking the time. I think I left it a little bit unclear what exactly I am trying to do, I updated the question accordingly. Sorry for the confusion.
            – Silvester
            Nov 19 '18 at 13:56












          • @Silvester, my bad. I mixed select_subclasses and select_related. Now I have fix it. Sorry.
            – dani herrera
            Nov 19 '18 at 14:52


















          • With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once?
            – Silvester
            Nov 19 '18 at 9:05










          • hi @Silvester, I have updated answer. Enjoy.
            – dani herrera
            Nov 19 '18 at 10:40










          • Thank you for taking the time. I think I left it a little bit unclear what exactly I am trying to do, I updated the question accordingly. Sorry for the confusion.
            – Silvester
            Nov 19 '18 at 13:56












          • @Silvester, my bad. I mixed select_subclasses and select_related. Now I have fix it. Sorry.
            – dani herrera
            Nov 19 '18 at 14:52
















          With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once?
          – Silvester
          Nov 19 '18 at 9:05




          With this pattern, Django performs an additional DB query when I access the related object. Since I have many D objects, this gets quite expensive. Do you know if there is any way to fetch them all at once?
          – Silvester
          Nov 19 '18 at 9:05












          hi @Silvester, I have updated answer. Enjoy.
          – dani herrera
          Nov 19 '18 at 10:40




          hi @Silvester, I have updated answer. Enjoy.
          – dani herrera
          Nov 19 '18 at 10:40












          Thank you for taking the time. I think I left it a little bit unclear what exactly I am trying to do, I updated the question accordingly. Sorry for the confusion.
          – Silvester
          Nov 19 '18 at 13:56






          Thank you for taking the time. I think I left it a little bit unclear what exactly I am trying to do, I updated the question accordingly. Sorry for the confusion.
          – Silvester
          Nov 19 '18 at 13:56














          @Silvester, my bad. I mixed select_subclasses and select_related. Now I have fix it. Sorry.
          – dani herrera
          Nov 19 '18 at 14:52




          @Silvester, my bad. I mixed select_subclasses and select_related. Now I have fix it. Sorry.
          – dani herrera
          Nov 19 '18 at 14:52


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53341329%2fdjango-select-related-with-multi-table-inheritance%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

          MongoDB - Not Authorized To Execute Command

          How to fix TextFormField cause rebuild widget in Flutter

          in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith