用django

时间:2017-05-23 12:43:27

标签: django

我是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。哪个不一样。

向像我这样的初学者表示赞赏。

2 个答案:

答案 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()) )。你可以将我在这个答案中说的所有内容打包成一个整齐的模板标签,如果你需要或想要它将呈现树木。

注意:此方法的一个明显限制是,如果未选择所有项目,它将无法正常运行。如果您选择所有项目的子集,并且如果您选择子节点并省略其父节点,则子节点将永远不会显示。