JavaRush /Курсы /Модуль 3: Django /Передача данных в шаблоны через context

Передача данных в шаблоны через context

Модуль 3: Django
5 уровень , 2 лекция
Открыта

В предыдущих лекциях мы разобрались с основами шаблонов Django и простой передачей данных через контекст. А сегодня пойдём дальше и научимся работать со сложными структурами данных: объектами с методами, вложенными словарями и списками. Ещё разберёмся с типичными ошибками и научимся их исправлять.

Работа со сложными структурами данных

В реальных проектах редко приходится передавать в шаблон просто строку или число. Чаще всего это объекты моделей, сложные словари или вложенные списки. Давайте разберём, как Django справляется с такими данными.

Например, у нас есть объект продукта с методами и связанными данными:

class Product:
    def __init__(self, name, price):
        self.name = name
        self.price = price
        self.reviews = []

    def get_price_with_discount(self):
        return self.price * 0.9

    def add_review(self, text, rating):  # Метод с аргументами
        self.reviews.append({"text": text, "rating": rating})

def catalog_view(request):
    product = Product("Телефон", 1000)
    product.add_review("Отличный!", 5)
    return render(request, "catalog.html", {"product": product})

В шаблоне можно использовать атрибуты и методы без аргументов:

<h2>{{ product.name }}</h2>
<p>Цена: {{ product.price }}</p>
<p>Со скидкой: {{ product.get_price_with_discount }}</p>

<!-- Но этот вызов НЕ сработает, так как метод требует аргументов -->
{{ product.add_review }}
Важно:

Django из соображений безопасности позволяет вызывать только методы объектов, которые не требуют аргументов.

Вложенные структуры и циклы

Часто в шаблон нужно передать данные с несколькими уровнями вложенности. Например, каталог товаров с категориями и подкатегориями. Django отлично справляется с такими структурами:

def catalog_view(request):
    catalog = {
        'electronics': {
            'name': 'Электроника',
            'categories': [
                {
                    'name': 'Смартфоны',
                    'products': [
                        {'name': 'iPhone', 'price': 999},
                        {'name': 'Samsung', 'price': 899}
                    ]
                },
                {
                    'name': 'Ноутбуки',
                    'products': [
                        {'name': 'MacBook', 'price': 1299},
                        {'name': 'Dell XPS', 'price': 1199}
                    ]
                }
            ]
        }
    }
    return render(request, 'catalog.html', {'catalog': catalog})

В шаблоне мы можем использовать вложенные циклы и проверки:

<h1>{{ catalog.electronics.name }}</h1>

{% for category in catalog.electronics.categories %}
    <h2>{{ category.name }}</h2>

    <ul>
    {% for product in category.products %}
        <li>
            {{ product.name }} — ${{ product.price }}
            {% if product.price > 1000 %}
                <span>Премиум товар</span>
            {% endif %}
        </li>
    {% empty %}
        <li>В этой категории пока нет товаров</li>
    {% endfor %}
    </ul>
{% endfor %}

Обратите внимание на тег {% empty %} — он показывает альтернативный контент, если список пустой. Это удобнее, чем проверять длину списка через if.

Ловушки и как их избегать

При работе со сложными данными в шаблонах часто встречаются подводные камни. Давайте разберём основные проблемы и способы их решения:

  1. Безопасный доступ к вложенным данным:
    def view(request):
    data = {
        'user': {
            'profile': None  # Допустим, профиль не создан
        }
    }
    return render(request, 'template.html', {'data': data})
    
<!-- Рискованный вариант -->
{{ data.user.profile.name }}  <!-- Вызовет ошибку! -->

<!-- Безопасный вариант -->
{% if data.user.profile %}
    {{ data.user.profile.name }}
{% else %}
    <p>Профиль не заполнен</p>
{% endif %}
  1. Работа с методами объектов:

    class Article:
        def get_comments_count(self):
            return len(self.comments)
    
        def add_comment(self, text):  # Метод с аргументом
            self.comments.append(text)
<!-- Сработает -->
<p>Комментариев: {{ article.get_comments_count }}</p>

<!-- НЕ сработает, так как метод требует аргумент -->
<p>{{ article.add_comment }}</p>
  1. Отладка сложных структур:
    def view(request):
    complex_data = get_complex_data()
    print("Debug data:", complex_data)  # Поможет при отладке
    return render(request, 'template.html', {'data': complex_data})
    

Практические примеры

Давайте разберём реальный пример — панель администратора с информацией о курсах и студентах:

def admin_dashboard(request):
    courses_data = {
        'python': {
            'name': 'Python Pro',
            'groups': [
                {
                    'name': 'PY-1',
                    'students': [
                        {
                            'name': 'Анна',
                            'progress': 95,
                            'has_homework': True,
                            'completed_tasks': [
                                {'title': 'Django Models', 'score': 100},
                                {'title': 'API Views', 'score': 90}
                            ]
                        },
                        {
                            'name': 'Борис',
                            'progress': 80,
                            'has_homework': False,
                            'completed_tasks': []
                        }
                    ]
                }
            ]
        }
    }
    return render(request, 'dashboard.html', {'courses': courses_data})

А вот как мы можем это отобразить в шаблоне, используя все изученные техники:

{% for course_id, course in courses.items %}
    <h2>{{ course.name }}</h2>

    {% for group in course.groups %}
        <div class="group-card">
            <h3>Группа {{ group.name }}</h3>

            {% for student in group.students %}
                <div class="student {% if student.progress < 85 %}needs-attention{% endif %}">
                    <h4>{{ student.name }}</h4>

                    <!-- Безопасный доступ к данным -->
                    <p>Прогресс: {{ student.progress }}%</p>

                    <!-- Вложенные циклы с empty -->
                    {% for task in student.completed_tasks %}
                        <div>✓ {{ task.title }} ({{ task.score }}%)</div>
                    {% empty %}
                        <div>Нет выполненных заданий</div>
                    {% endfor %}

                    <!-- Сложные условия -->
                    {% if student.has_homework and student.progress < 90 %}
                        <div class="warning">Требуется внимание ментора!</div>
                    {% endif %}
                </div>
            {% empty %}
                <p>В группе пока нет студентов</p>
            {% endfor %}
        </div>
    {% endfor %}
{% endfor %}

Продвинутые приёмы отладки

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

Debug-режим Django

# settings.py
DEBUG = True

# views.py
def complex_view(request):
    data = get_complex_data()
    context = {'data': data}
    if settings.DEBUG:
        print("Context data:", context)  # Увидим в консоли при разработке
    return render(request, 'template.html', context)

Отладочные теги в шаблоне

<!-- Временно добавляем для проверки структуры данных -->
<pre>
    {{ complex_data|pprint }}
</pre>

<!-- Или проверяем конкретный участок -->
{% if debug %}
    <div class="debug-info">
        Текущий объект: {{ current_object|pprint }}
    </div>
{% endif %}

Специальные комментарии

{# Этот комментарий не попадёт в HTML #}
{% comment %}
    Тут можно писать много строк
    И проверять разные варианты
    Временно отключая код
{% endcomment %}

Вскоре мы рассмотрим наследование шаблонов — мощный инструмент для создания сложных и поддерживаемых интерфейсов!

1
Задача
Модуль 3: Django, 5 уровень, 2 лекция
Недоступна
Список элементов
Список элементов
1
Задача
Модуль 3: Django, 5 уровень, 2 лекция
Недоступна
Условие и доступ к объекту
Условие и доступ к объекту
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Максим Уровень 55
29 октября 2025
    {{ complex_data|pprint }}  # как будо лишняя "p"