Django: select_related with multi table inheritance
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 A
are 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
add a comment |
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 A
are 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
add a comment |
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 A
are 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
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 A
are 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
python django inheritance
edited Nov 19 '18 at 13:56
asked Nov 16 '18 at 15:55
Silvester
31629
31629
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
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 )
]
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 mixedselect_subclasses
andselect_related
. Now I have fix it. Sorry.
– dani herrera
Nov 19 '18 at 14:52
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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 )
]
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 mixedselect_subclasses
andselect_related
. Now I have fix it. Sorry.
– dani herrera
Nov 19 '18 at 14:52
add a comment |
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 )
]
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 mixedselect_subclasses
andselect_related
. Now I have fix it. Sorry.
– dani herrera
Nov 19 '18 at 14:52
add a comment |
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 )
]
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 )
]
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 mixedselect_subclasses
andselect_related
. Now I have fix it. Sorry.
– dani herrera
Nov 19 '18 at 14:52
add a 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?
– 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 mixedselect_subclasses
andselect_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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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