首页 > 解决方案 > 模板问题中的Django递归关系嵌套

问题描述

首先,我想对 stack-overflow 的所有人表示感谢。我已经研究并能够找到许多关于 Django 递归关系的问题的答案;从模型创建到视图,再到现在的模板。我是 Python 新手,因此是 Django 新手。因此,我感谢您在回答其他人提出的问题时提供的详细示例。

tl;博士

我需要有一个与另一个模型有外键关系的嵌套(有序)列表。我尝试使用递归外键来“自我”,但无法通过我的研究完成任务。感谢@somecallitblues(有人能告诉我如何评价他吗?)指出 Django-mptt,我能够解决这个问题。

(我不知道是否或如何将此问题标记为已回答和/或我是否应该更改标题以便其他人能够搜索他们是否有同样的问题。我可以在格式化我的问题时使用一些帮助/或正确的提问方式。任何指针都会有所帮助。)

楷模

    from mptt.models import TreeForeignKey, MPTTModel

    class Topic(models.Model):
        wherein = models.CharField()            
        partof = models.CharField()            
        title = models.CharField()            
        slug = models.SlugField()

    class TextNode(MPTTModel):
        topic = models.ForeignKey(Topic)
        parent = TreeForeignKey(
                "self",
                on_delete=models.CASCADE,
                related_name="children",
                related_query_name="child",
                null=True,
                blank=True,
            )    
        body = models.TextField()

看法

    def topic_node_list(request, slug):
        topics = Topic.objects.filter(slug__exact=slug)
        textnodes = TextNode.objects.filter(topic__slug__exact=slug)

        return render(request, "node_test.html", {"topics": topics, "textnodes": textnodes})    

模板

{% load mptt_tags %}

<ul>
    {% for topic in topics %}
        <h2>{{ topic.title }}</h2>
        <ul>
        {% recursetree textnodes %}
            <li>
              {{ node.body}}
            {% if not node.is_leaf_node %}
                <ul class="children">
                    {{ children }}
                </ul>
            {% endif %}
            </li>
        {% endrecursetree %}
        </ul>
    {% endfor %}
</ul>

网址.py

urlpatterns = [
    path("nodes/<slug:slug>/", views.topic_node_list, name="nodes"),    
    path("", views.home, name="home"),
    path('admin/', admin.site.urls),
 ]

一切都很好!所以再次感谢@somecallitblues!

但是!我想改为

到有序列表,并根据嵌套级别更改类型。我希望第一个有序列表是 1.,2.,3 下一个是 a., b., c.,然后是 i.,ii。iii. 等可以通过 JavaScript 或 jQuery 完成吗?我什至不知道在哪里寻找或在我的搜索引擎中搜索什么。

这是我第一次用 Python 做项目。我在 12 月刚开始学习,我一直在做简单的博客,需要挑战,天哪,天哪,我学到了很多东西!我正在从一场重大疾病中恢复过来,并且已经失去了近十年的工作时间,所以要重新回到正轨一直很有挑战性。Python 极大地帮助了我恢复肌肉记忆。

结束 tl;博士

我正在尝试创建一个“报告”(因为缺少更好的术语)应用程序。它有一个目录,介绍性的,无论你想要多少部分,参考书目,脚注,索引,词汇表等。我还有一个应用程序可以解决可以提出的问题以及回答上述问题的能力,这就是我的地方我有一个问题和我的问题的基础。我的模型、视图和模板代码将在下面添加。(如果我能弄清楚如何发布代码)。

我有一个主题模型和一个身体模型。主题模型是问题的主题。Body 模型是存储问题文本的地方。每个问题可能有也可能没有子问题。Body 模型具有 Subject 模型的外键。Body 模型有一个“self”的递归外键。这种关系运作良好,尽管我确实有一个“我该怎么做”的问题,我将在下面列出。**

对于视图,我有一个 Subject 模型的通用 ListView 并为 Body 模型添加了额外的上下文。

模板是我的问题的基础。我可以嵌套被问问题的“主题”和“正文”的有序列表。正好。这是我发布问题(或子问题)的孩子的地方。

该模板将在有序列表中列出父问题及其子问题。然后孩子们开始列出作为父母的问题,所以本质上他们被发布了两次。一次正确地作为子问题,然后错误地作为父问题(尽管我想知道如何将子问题列为子问题的父问题(孙子关系?)。)

我曾想过同时使用自定义模型管理器或类方法来从孩子中挑选出父母,但我将如何去做呢?正如我所说,我是 python 和 Django 的新手,所以我不知道。

我正在使用: Django 版本:2.1.8 Django-pyodbc-azure 2.1 python 3.7.2

这是我的代码:

楷模

class Subject(models.Model):
    ...
        wherein = models.CharField(
                max_length=3,
                choices=WHERE,
                default=SECTION,
                help_text="Where in the report",
                )
        partof = models.CharField(
                max_length=5,
                choices=PART_OF,
                default=QUESTION,
                help_text="Is this a question or answer?")
        title = models.CharField(
                max_length=80,
                help_text="What is the subject of the question",
                )
        slug = models.SlugField(
                max_length=80,
                help_text="This is what the url will be"
                )
    class Body(models.Model):
        subject = models.ForeignKey(
                Subject,
                on_delete=models.CASCADE,
                verbose_name="subject of",
                help_text="What subject does this text relate to?"
                )
        parent = models.ForeignKey(
                "self",
                on_delete=models.CASCADE,
                verbose_name="subsection of",
                related_name="subsections",
                related_query_name="subsection",
                null=True,
                blank=True,
                )
        text = models.TextField(
                max_length=1500,
                help_text="Text of the paragraph",)

看法

    class QuestionList(ListView):
        queryset = Subject.objects.filter(id=2)
        template_name = "questions/questions_list.html"
        context_object_name = "subjects"

        def get_context_data(self, *args, object_list=None, **kwargs):
            context = super(QuestionDetail, self).get_context_data(**kwargs)
            context["bodies"] = Body.objects.filter(subject__partof__exact="QUES")
            return context

模板

    <ol type="1">
        {% for subject in subjects %}
                <li><b>{{ subject.title }}</b></li>
    <ol type="a">
        {% for body in bodies %} # I believe this is where I need to filter for just parents
            <li>{{ body.text }}</li>
            <ol type="i">
                {% for sub in body.subsections.all %}
                    <li>{{ sub.text }}</li>
                {% endfor %}
            </ol>
        {% endfor %}
    </ol>
    </ol>
    {% endfor %}

我想有一个进一步嵌套的选项(有父母的孩子的孩子)。

我应该为父母添加额外的上下文: Body.objects.filter(parent_id__isnull=True)?如果是这样,在模板中,这将如何处理与孩子的关系?(嵌套列表)。

** 一个附带问题:我如何让“孩子”成为他们自己的“孩子”的父母?以及如何将它们嵌套在模板中?

我希望我已经正确地提出了我的问题,我尝试尽可能多地发布,我希望这是一种简单的解决方法。如果有什么我遗漏的,请随时询问!

谢谢!

更新:这是要呈现为 html 的模板

# The first ol

    <li>1. This would be the topic a question</li>
           <li>a. This would be the parent question.</li>
                 <li>i. This would be the child of the parent question a.</li>
                 <li> ii. This would also be a child of the parent question a.</li>
           <li>b. This would be the second parent question</li>
           <li>c. This would be the third parent question</li>
                  <li>i. This would be the child of the parent question c.</li>
                  <li> ii. This would also be a child of the parent question c.</li>
           <li>d. … and so on</li>
    <li>2. This would be the next topic of a question</li>

更新 2:我意识到我没有更新现在的渲染方式。这里是:

    <li>1. This would be the topic a question</li>
           <li>a. This would be the parent question.</li>
                 <li>i. This would be the child of the parent question a.</li>
                 <li> ii. This would also be a child of the parent question a.</li>
           <li>b. This would be the second parent question</li>
           <li>c. This would be the third parent question</li>
                  <li>i. This would be the child of the parent question c.</li>
                  <li> ii. This would also be a child of the parent question c.</li>
           <li>d. … and so on</li>
           <li>e. This would be the child of the parent question a.</li>
           <li>f. This would also be a child of the parent question a.</li>           
           <li>g. This would be the child of the parent question c.</li>
           <li>h. This would also be a child of the parent question c.</li>
           <li>i. … and so on</li>
    <li>2. This would be the next topic of a question</li>

我目前正在阅读有关添加自定义模型管理器的 Django 文档。有点迷茫,但我会坚持尝试新的做事方式。就像我说的那样,我此时有点迷茫,真的需要一些帮助。

更新 3

我接受了@somecallitblues 的建议,并花时间浏览了 Django-treebead 和 Django-mptt。使用 Treebeard,我无法弄清楚如何使用模板。使用 mppt 我能够构建模型,但无法将两个模型连接在一起以在模板中显示,并且视图我必须硬编码 topic_id。我觉得我错过了什么。谁能指出我的问题在哪里?我正在阅读所有文档,但不了解在何处以及如何应用这些方法。我对 web 开发非常陌生,而且我是 python 的新手。

我将发布我现在拥有的内容,如果有人可以给我一些关于我应该研究的内容的指示,我将不胜感激。

对于模型,主题仍然是相同的,只是它被命名为主题,所以我不会重新发布:

更新的车身模型:

class BodyNode(MPTTModel):
    topic = models.ForeignKey(
            Topic,
            on_delete=models.CASCADE,
            verbose_name="Of topic",
            help_text="What topic is being discussed?",
            )    
    text = models.TextField(
            max_length=750,
            help_text="Content of the paragraph",
            )
    parent = TreeForeignKey(
            "self",
            on_delete=models.CASCADE,
            related_name="children",
            blank=True,
            null=True,
            )

看法:

def topic_list(request):
    bodynodes = BodyNode.objects.filter(topic_id=2)

    return render(request, "mpttapp/topic_list.html", {"bodynodes": bodynodes})

模板:

 <ol class="root" type="a">
                    {% recursetree bodynodes %}
                        <li>
                            {{ node.text }}
                            {% if not node.is_leaf_node %}
                                    <ol type="i" class="children">
                                    {{ children }}
                                    </ol>
                            {% endif %}
                        </li>
                    {% endrecursetree %}
                </ol>

现在,列表按原样显示,但仅适用于 topid_id=2。我需要它是动态的,并且能够为 url 添加 slug 字段,以及能够使用主题模型中的标题字段,所以我已经成功了一半。

我确实要感谢@somecallitblues 对我的帮助,我觉得使用 mptt 是可行的方法,因为如果需要,我将能够进行更深的嵌套。我只是觉得我有点过头了,但我真的决心解决这个问题。我只需要一些指示。

更新 4

我想我已经弄清楚了关系问题。我将使用 BodyNode 中的 TreeForeignKey 将主题模型制作成 MPTTModel。我认为与主题模型的关系是我遇到的嵌套问题。由于应用程序本身是“某种”树/目录对象,这可能是我挣扎的原因。如果可行,我明天会再次更新,我真的很想解决这个问题,并让这个主题对遇到同样问题的其他人有所帮助。

我确实花了很多时间阅读 Django-project 网站上的文档,但在构建模板/视图时我仍然有点困惑。如果有人知道一个好的教程网站或一本好书,而不仅仅是建立一个简单的博客,我将不胜感激。

标签: djangopython-3.xdjango-modelsdjango-templatesdjango-views

解决方案


推荐阅读