← Назад к вопросам

За что отвечает каждая буква в MTV

1.0 Junior🔥 191 комментариев
#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Архитектурный паттерн MTV (Model-Template-View)

МTV — это архитектурный паттерн, используемый в Django. Это вариант паттерна MVC, адаптированный специально для Django. Каждая буква отвечает за отдельный компонент системы.

M — Model (Модель)

Отвечает за:

  • Представление данных и бизнес-логики
  • Взаимодействие с базой данных
  • Валидацию данных
  • Бизнес-правила

Model — это класс, который наследуется от django.db.models.Model:

from django.db import models

class Article(models.Model):
    """Модель статьи"""
    title = models.CharField(max_length=200)
    content = models.TextField()
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    is_published = models.BooleanField(default=False)
    
    class Meta:
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["is_published", "-created_at"]),
        ]
    
    def __str__(self):
        return self.title
    
    def get_absolute_url(self):
        """URL статьи"""
        return f"/articles/{self.id}/"
    
    def is_recent(self):
        """Бизнес-логика: проверить, свежая ли статья"""
        from django.utils import timezone
        from datetime import timedelta
        return self.created_at > timezone.now() - timedelta(days=7)

Ответственность Model:

  • Определение структуры данных (поля, связи)
  • ORM операции (save, delete, filter, get)
  • Валидация на уровне БД (constraints, validators)
  • Методы бизнес-логики

T — Template (Шаблон)

Отвечает за:

  • Отображение данных пользователю
  • HTML разметка
  • Логика представления (conditionals, loops)
  • Интеграция CSS и JavaScript

Template — это HTML файл с Django шаблонизатором:

<!-- templates/article_detail.html -->
<!DOCTYPE html>
<html>
<head>
    <title>{{ article.title }}</title>
    <link rel="stylesheet" href="{% static "style.css" %}">
</head>
<body>
    <h1>{{ article.title }}</h1>
    
    <p>Автор: <strong>{{ article.author.get_full_name }}</strong></p>
    <p>Дата: {{ article.created_at|date:"Y-m-d" }}</p>
    
    {% if article.is_recent %}
        <span class="badge">Свежая статья!</span>
    {% endif %}
    
    <div class="content">
        {{ article.content|safe }}
    </div>
    
    {% if user.is_authenticated %}
        <a href="{% url "edit_article" article.id %}">Редактировать</a>
    {% else %}
        <p>Пожалуйста, <a href="{% url "login" %}">авторизуйтесь</a> для редактирования</p>
    {% endif %}
    
    <h3>Комментарии</h3>
    {% for comment in article.comments.all %}
        <div class="comment">
            <p>{{ comment.author }}: {{ comment.text }}</p>
        </div>
    {% empty %}
        <p>Нет комментариев</p>
    {% endfor %}
</body>
</html>

Ответственность Template:

  • HTML структура
  • Отображение переменных из context
  • Условная логика (if/else, for)
  • Filters и template tags
  • CSS классы и статические файлы

V — View (Представление)

Отвечает за:

  • Обработка HTTP запросов
  • Получение данных из Model
  • Подготовка контекста для Template
  • Бизнес-логика контроллера (не основной бизнес, а логика запроса)
  • Возврат HTTP ответа

Function-based View (FBV):

from django.shortcuts import render, get_object_or_404
from django.http import HttpResponse
from .models import Article

def article_list(request):
    """Список всех статей"""
    # Model: получение данных
    articles = Article.objects.filter(is_published=True).order_by("-created_at")
    
    # Фильтрация по поиску
    search = request.GET.get("search")
    if search:
        articles = articles.filter(title__icontains=search)
    
    # Пагинация
    paginate_by = 10
    page = request.GET.get("page", 1)
    # ... логика пагинации
    
    # Подготовка context для Template
    context = {
        "articles": articles,
        "search": search,
    }
    
    # Template: рендеринг с данными
    return render(request, "article_list.html", context)

def article_detail(request, article_id):
    """Детальный вид статьи"""
    # Model
    article = get_object_or_404(Article, id=article_id, is_published=True)
    
    # Обновление счётчика просмотров
    article.views += 1
    article.save(update_fields=["views"])
    
    # Context
    context = {"article": article}
    
    # Template
    return render(request, "article_detail.html", context)

Class-based View (CBV):

from django.views import View
from django.views.generic import ListView, DetailView

class ArticleListView(ListView):
    """Список статей с готовой логикой"""
    model = Article
    template_name = "article_list.html"
    context_object_name = "articles"
    paginate_by = 10
    
    def get_queryset(self):
        """Model: фильтрация данных"""
        queryset = Article.objects.filter(is_published=True)
        
        search = self.request.GET.get("search")
        if search:
            queryset = queryset.filter(title__icontains=search)
        
        return queryset
    
    def get_context_data(self, **kwargs):
        """Template: дополнительный контекст"""
        context = super().get_context_data(**kwargs)
        context["search"] = self.request.GET.get("search", "")
        return context

class ArticleDetailView(DetailView):
    """Детальный вид статьи"""
    model = Article
    template_name = "article_detail.html"
    context_object_name = "article"
    
    def get_queryset(self):
        return Article.objects.filter(is_published=True)
    
    def get(self, request, *args, **kwargs):
        """Обновление просмотров перед рендерингом"""
        response = super().get(request, *args, **kwargs)
        self.object.views += 1
        self.object.save(update_fields=["views"])
        return response

Ответственность View:

  • Обработка HTTP запроса
  • Вызовы Model для получения данных
  • Бизнес-логика для подготовки данных
  • Подготовка контекста
  • Возврат HTTP ответа

Архитектурная диаграмма MTV

HTTP Request
    ↓
[View (обработчик)]
    ↓
[Model (данные)] ← Запрос к БД
    ↓
[Template (HTML)] ← Render с context
    ↓
HTTP Response (HTML)

Сравнение MTV с MVC

MTV (Django)MVCРоль
ModelModelДанные и бизнес-логика
TemplateViewПредставление данных
ViewControllerОбработка запросов и логика

Отличие: в MVC вью отвечает за представление, а в Django вью отвечает за логику обработки (как контроллер).

Практический пример полного цикла

# models.py
class Comment(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name="comments")
    author = models.CharField(max_length=100)
    text = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

# views.py
def article_detail(request, article_id):
    # View: получение статьи из Model
    article = get_object_or_404(Article, id=article_id)
    
    # View: получение комментариев из Model
    comments = article.comments.all().order_by("-created_at")
    
    # View: обработка POST запроса
    if request.method == "POST":
        author = request.POST.get("author")
        text = request.POST.get("text")
        # Model: создание комментария
        Comment.objects.create(article=article, author=author, text=text)
        # Redirect или re-render
    
    # View: подготовка контекста
    context = {"article": article, "comments": comments}
    
    # Template: рендеринг
    return render(request, "article_detail.html", context)

# template: article_detail.html
# Цикл по комментариям (Template логика)
{% for comment in comments %}
    <div>{{ comment.author }}: {{ comment.text }}</div>
{% endfor %}

Выводы

  • Model = Данные и бизнес-логика
  • Template = HTML и представление
  • View = Логика обработки запросов
  • MTV помогает разделить ответственность
  • Каждый компонент можно тестировать отдельно