我是Django的新手,很容易迷失。
我有这个应用程序有项目。它们被设置为具有父子关系的列表。
稍后我想显示附加到项目的任务。但现在。我甚至无法弄清楚如何展示亲子。
这是我的简化模型
class Item(models.Model):
item_title = models.Charfield()
item_parent = models.ForeignKey('self')
我想将它们显示为:
Item 1
- item 2
- item 3
-- item 4
-- item 5
Item 6
- item 7
-- item 8
--- item 9
我尝试制作一个带有Item.objects.all()。order_by(' item_parent')
的视图带有FOR-IN的模板。但我不知道如何分开展示第一个父母,然后是另一个孩子,而另一个孩子就是这样。
我只是设法通过item_parent按顺序列出everthing。哪个不一样。
向像我这样的初学者表示赞赏。
答案 0 :(得分:2)
您需要使用:
item_parent__self_set
每个item_parent的平均值,你有childs列表(如果是query_set,则为_set) 定义ForeignKey时,会自动获得反向关系。
你可以做一些更简单的事情:
class Item(models.Model):
item_title = models.Charfield()
item_parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
你找回:
for item in Item.objects.filter(item_parent__isnull=True):
print item.item_title
for child in item.children.all():
print child.item_title
答案 1 :(得分:2)
如果性能不是问题,那么基于MaximeK答案的解决方案是最简单的。由于您以递归方式查询数据库,因此性能不佳。对于非常少量的物品,这是可以的。
一种更有效的方式,也可以支持无限深度的孩子,一次获取所有项目,然后创建一个树,然后您可以遍历以按顺序打印项目。编写的代码更多,但如果不能直接帮助解决问题,则可能具有教育意义。
第一步:我们为每个没有根(存储在根目录中)的项目生成tree。旁注:我们可以将这些树视为从一个根节点开始的一棵大树,其中所有项目都没有父母作为孩子,但为了简单起见,我们不这样做。
references = {}
roots = []
items = Item.objects.all()
for item in items:
# get or make a new node
if item.pk in references:
n = references[n]
n.item = item
else:
n = Node(children=[], item=item)
references[item.pk] = n
if item.item_parent is None:
# if item is root (no parent)
roots.append(n)
else:
# if item has a parent
if item.item_parent_id in references:
# item parent already seen
parent_n = references[item.item_parent_id]
else:
# item not seen yet
parent_n = Node(children=[], item=None)
parent_n.children.append(n)
第二步:我们遍历树深度优先
def dfs(root, level=0):
print("-"*level, root.item.item_title)
for node in root.children:
dfs(node, level+1)
for root in roots:
dfs(root)
这只是打印前面带有item_title
的{{1}}来表示缩进级别。我生成了一些随机项,输出如下:
-
我不知道如何在Django模板中执行此操作,但我们可以生成如下所示的HTML:
python mouse cat
- mouse monitor car
-- blue car cat
green machine computer
- monitor green yellow
yellow pen blue
- mouse cat yellow
yellow blue green
- cat monitor python
-- blue yellow python
-- machine green cat
--- monitor blue python
-- machine computer mouse
-- machine car blue
car pen yellow
生成上述HTML的深度优先遍历。我把它写成一个类以避免全局变量。
<ul>
<li>pen monitor cat
<ul>
<li>computer mouse machine</li>
<li>yellow python car
<ul>
<li>monitor python pen</li>
<li>mouse blue green</li>
<li>python blue cat</li>
</ul>
</li>
</ul>
</li>
<li>mouse computer cat</li>
<li>computer python car
<ul>
<li>pen green python
<ul>
<li>mouse computer machine</li>
</ul>
</li>
<li>machine yellow mouse</li>
</ul>
</li>
<li>yellow python monitor</li>
<li>car cat pen
<ul>
<li>pen machine blue
<ul>
<li>mouse computer machine</li>
</ul>
</li>
</ul>
</li>
</ul>
要在网页上呈现,您只需通过上下文将HTML发送到模板,然后使用安全标记(class TreeHtmlRender:
def __init__(self, roots):
self.roots = roots
def traverse(self):
self.html_result = "<ul>"
for root in self.roots:
self.dfs(root, 0)
self.html_result += "</ul>"
return self.html_result
def dfs(self, root, level=0):
self.html_result += ("<li>%s" % root.item.item_title)
if len(root.children) > 0:
self.html_result += "<ul>"
for node in root.children:
self.dfs(node, level+1)
self.html_result += "</ul>"
self.html_result += "</li>"
r = TreeHtmlRender(roots)
print(r.traverse())
)。你可以将我在这个答案中说的所有内容打包成一个整齐的模板标签,如果你需要或想要它将呈现树木。
注意:此方法的一个明显限制是,如果未选择所有项目,它将无法正常运行。如果您选择所有项目的子集,并且如果您选择子节点并省略其父节点,则子节点将永远不会显示。