Django ORM annotation with tree traversal
I'm using the django-mptt library to make categories for my project. The model is pretty simple:
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
class Category(MPTTModel):
name = models.CharField('Name', max_length=100, unique=True)
color = models.CharField(
'Color',
max_length=100,
blank=True,
null=True
)
parent = TreeForeignKey(
'self',
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='children'
)
class MPTTMeta:
order_insertion_by = ['name']
Category color is optional and should be inherited from parent, if undefined. So just to illustrate:
Main Category 1 (red) -> Subcategory 1
-> Subcategory 2 (blue)
-> Subcategory 3 (yellow) -> Subcategory 4
Subcategory 4 has no color defined and it inherits subcategory 3 color (yellow).
Subcategory 1 inherits color from Main Category 1 (blue), etc.
In my view i have the root category and then build a tree using get_descendants(include_self=True)
.
How can i annotate color for each category of <TreeQuerySet>
?
For one model i have the following method:
@property
def inherited_color(self):
if self.color:
return self.color
return (self
.get_ancestors(ascending=True, include_self=True)
.filter(color__isnull=False)
.values_list('color', flat=True)
.first())
But when this method is called for a list of categories it results in a lot of database queries!
This is an example from django shell:
>>> category
<Category: 3>
>>> category.color is None
True
>>> category.get_family().values_list('name', 'color')
<TreeQuerySet [('1', '#51DCFF'), ('2', None), ('3', None)]>
>>> category.inherited_color
'#51DCFF'
django django-mptt
add a comment |
I'm using the django-mptt library to make categories for my project. The model is pretty simple:
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
class Category(MPTTModel):
name = models.CharField('Name', max_length=100, unique=True)
color = models.CharField(
'Color',
max_length=100,
blank=True,
null=True
)
parent = TreeForeignKey(
'self',
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='children'
)
class MPTTMeta:
order_insertion_by = ['name']
Category color is optional and should be inherited from parent, if undefined. So just to illustrate:
Main Category 1 (red) -> Subcategory 1
-> Subcategory 2 (blue)
-> Subcategory 3 (yellow) -> Subcategory 4
Subcategory 4 has no color defined and it inherits subcategory 3 color (yellow).
Subcategory 1 inherits color from Main Category 1 (blue), etc.
In my view i have the root category and then build a tree using get_descendants(include_self=True)
.
How can i annotate color for each category of <TreeQuerySet>
?
For one model i have the following method:
@property
def inherited_color(self):
if self.color:
return self.color
return (self
.get_ancestors(ascending=True, include_self=True)
.filter(color__isnull=False)
.values_list('color', flat=True)
.first())
But when this method is called for a list of categories it results in a lot of database queries!
This is an example from django shell:
>>> category
<Category: 3>
>>> category.color is None
True
>>> category.get_family().values_list('name', 'color')
<TreeQuerySet [('1', '#51DCFF'), ('2', None), ('3', None)]>
>>> category.inherited_color
'#51DCFF'
django django-mptt
add a comment |
I'm using the django-mptt library to make categories for my project. The model is pretty simple:
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
class Category(MPTTModel):
name = models.CharField('Name', max_length=100, unique=True)
color = models.CharField(
'Color',
max_length=100,
blank=True,
null=True
)
parent = TreeForeignKey(
'self',
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='children'
)
class MPTTMeta:
order_insertion_by = ['name']
Category color is optional and should be inherited from parent, if undefined. So just to illustrate:
Main Category 1 (red) -> Subcategory 1
-> Subcategory 2 (blue)
-> Subcategory 3 (yellow) -> Subcategory 4
Subcategory 4 has no color defined and it inherits subcategory 3 color (yellow).
Subcategory 1 inherits color from Main Category 1 (blue), etc.
In my view i have the root category and then build a tree using get_descendants(include_self=True)
.
How can i annotate color for each category of <TreeQuerySet>
?
For one model i have the following method:
@property
def inherited_color(self):
if self.color:
return self.color
return (self
.get_ancestors(ascending=True, include_self=True)
.filter(color__isnull=False)
.values_list('color', flat=True)
.first())
But when this method is called for a list of categories it results in a lot of database queries!
This is an example from django shell:
>>> category
<Category: 3>
>>> category.color is None
True
>>> category.get_family().values_list('name', 'color')
<TreeQuerySet [('1', '#51DCFF'), ('2', None), ('3', None)]>
>>> category.inherited_color
'#51DCFF'
django django-mptt
I'm using the django-mptt library to make categories for my project. The model is pretty simple:
from django.db import models
from mptt.models import MPTTModel, TreeForeignKey
class Category(MPTTModel):
name = models.CharField('Name', max_length=100, unique=True)
color = models.CharField(
'Color',
max_length=100,
blank=True,
null=True
)
parent = TreeForeignKey(
'self',
on_delete=models.CASCADE,
null=True,
blank=True,
related_name='children'
)
class MPTTMeta:
order_insertion_by = ['name']
Category color is optional and should be inherited from parent, if undefined. So just to illustrate:
Main Category 1 (red) -> Subcategory 1
-> Subcategory 2 (blue)
-> Subcategory 3 (yellow) -> Subcategory 4
Subcategory 4 has no color defined and it inherits subcategory 3 color (yellow).
Subcategory 1 inherits color from Main Category 1 (blue), etc.
In my view i have the root category and then build a tree using get_descendants(include_self=True)
.
How can i annotate color for each category of <TreeQuerySet>
?
For one model i have the following method:
@property
def inherited_color(self):
if self.color:
return self.color
return (self
.get_ancestors(ascending=True, include_self=True)
.filter(color__isnull=False)
.values_list('color', flat=True)
.first())
But when this method is called for a list of categories it results in a lot of database queries!
This is an example from django shell:
>>> category
<Category: 3>
>>> category.color is None
True
>>> category.get_family().values_list('name', 'color')
<TreeQuerySet [('1', '#51DCFF'), ('2', None), ('3', None)]>
>>> category.inherited_color
'#51DCFF'
django django-mptt
django django-mptt
edited 17 hours ago
asked 21 hours ago
v01d
4117
4117
add a comment |
add a comment |
active
oldest
votes
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%2f53942918%2fdjango-orm-annotation-with-tree-traversal%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
active
oldest
votes
active
oldest
votes
active
oldest
votes
active
oldest
votes
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%2f53942918%2fdjango-orm-annotation-with-tree-traversal%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