Как отобразить несколько самосвязанных данных внешнего ключа в Django/HTML?

Я пытаюсь создать веб-приложение django для отображения различных данных (вопрос и некоторые дополнительные данные). Мои данные состоят из тела вопроса и отраслевого руководства, которое содержит несколько пунктов. Каждый пункт может содержать дополнительные подварианты и т. д.

Примерные данные:

Тело вопроса: Все ли были знакомы с расположением, назначением, испытанием и эксплуатацией противопожарных дверей? Отраслевое руководство:

  1. Эксплуатационная готовность
  2. Техническое обслуживание и тестирование
    • Регламентные проверки
    • Регламентное техническое обслуживание
      • Еженедельно
      • Ежемесячно
    • ...

Ниже представлены мои модели:

class BaseGuidance(models.model):
    text = models.CharField(max_length=2000)
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name="sub_options")

    class Meta:
        abstract = True

    def __str__(self):
        return self.text

class IndustryGuidance(BaseGuidance):
    pass

class Question(models.model):
    body = models.CharField(max_length=400)
    industry_guidance = models.ForeignKey(IndustryGuidance, on_delete=models.CASCADE, null=True, blank=True)

Вот мой вид, который отображает HTML:

def index(request):
    questions = Question.objects.all()
    industry_guidance = IndustryGuidance.objects.prefetch_related(
        'sub_options',
    ).all()
    return render(request, "sire/index.html",{
        "questions": questions,
        "industry_guidance": industry_guidance
    })

Ниже приведен мой HTML:

 <td scope="col"> 
            <ul class="list-group">
                {% for guidance in industry_guidance %}
                    <li>{{ guidance.text }} </li>
                    <ul>
                        {% for sub_option in guidance.sub_options.all %}
                            <li>{{ sub_option.text }}</li>
                        {% endfor %}
                    </ul>
                {% endfor %}
            </ul>
        </td>

Я действительно запутался в том, как именно я должен подойти к этой проблеме, чтобы получить все данные и отобразить их соответствующим образом.

Я попробовал prefetch_related, но мое веб-приложение не загрузилось, видимо, застряв в каком-то цикле for loop. Я также думаю о перестройке своих моделей, но не смог найти никаких рекомендаций или лучших практик по этому вопросу.

В конечном счете, я хотел бы отобразить каждый вопрос в таблице с относящимися к нему отраслевыми рекомендациями в виде списка. Каждый подвариант должен быть отступом в другом списке. Каждая пуля подварианта должна быть в другом списке, и так далее... Все данные, касающиеся вопроса, должны находиться в одной строке.

Я бы рекомендовал вам использовать django-mptt при работе с деревьями. Вот пример использования:

pip install django-mptt

добавьте «mptt» в ваш INSTALLED_APPS список в settings.py

INSTALLED APPS = [
    ...,
    "mptt",
]

Измените parent поле вашей BaseGuidance модели в models.py:


from mptt.fields import TreeForeignKey
from mptt.models import MPTTModel


class BaseGuidance(MPTTModel):
    text = models.CharField(max_length=2000)
    parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name="sub_options")

    class Meta:
        abstract = True

    class MPTTMeta:
        order_insertion_by = ['-id']
        parent_attr = 'parent'

    def __str__(self):
        return self.text

После изменения модели перенесите изменения:

python ./manage.py makemigrations
python ./manage.py migrate

Затем измените свои представления:

def index(request):
    questions = (
        Question.objects.select_related('industry_guidance')
        .prefetch_related('industry_guidance__sub_options')  # Fetch sub-options for the MPTT structure
    )

    context = []
    for question in questions:
        guidance_tree = (
            question.industry_guidance.get_descendants(include_self=True)
            if question.industry_guidance else None
        )
        context.append({
            "question": question,
            "guidance_tree": guidance_tree,
        })

    return render(request, "index.html", {"context": context})

И ваш sire/index.html файл:

{% for item in context %}
    <tr>
        <td>{{ item.question.body }}</td>
        <td>
            <ul>
                {% if item.guidance_tree %}
                    {% recursetree item.guidance_tree %}
                        <li>{{ node.text }}</li>
                        <ul>
                            {% for child in node.get_children %}
                                <li>{{ child.text }}</li>
                            {% endfor %}
                        </ul>
                    {% endrecursetree %}
                {% else %}
                    <li>No guidance available for this question.</li>
                {% endif %}
            </ul>
        </td>
    </tr>
{% endfor %}

Надеюсь, это вам поможет!

Вернуться на верх