← Назад к вопросам
Как создать представления (views) в Django?
1.0 Junior🔥 261 комментариев
#Django#REST API и HTTP
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как создать представления (views) в Django
View (представление) в Django — это функция или класс, которые получают Web request и возвращают Web response. Это основной компонент архитектуры MVC в Django, обрабатывающий бизнес-логику.
1. Function-Based Views (FBV)
Самый простой способ создать view — как функцию:
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render, get_object_or_404
from myapp.models import Post
# Простой view
def hello_world(request):
return HttpResponse("Hello, World!")
# View с шаблоном
def post_list(request):
posts = Post.objects.all()
return render(request, 'post_list.html', {'posts': posts})
# View с параметром из URL
def post_detail(request, post_id):
post = get_object_or_404(Post, id=post_id)
return render(request, 'post_detail.html', {'post': post})
# JSON response
def api_posts(request):
posts = list(Post.objects.values('id', 'title', 'content'))
return JsonResponse({'posts': posts})
# Обработка разных методов
def post_handler(request):
if request.method == 'GET':
posts = Post.objects.all()
return render(request, 'posts.html', {'posts': posts})
elif request.method == 'POST':
title = request.POST.get('title')
content = request.POST.get('content')
post = Post.objects.create(title=title, content=content)
return JsonResponse({'id': post.id, 'message': 'Created'})
2. Class-Based Views (CBV)
Для сложной логики лучше использовать классы:
from django.views import View
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
# Простой класс-view
class PostListView(View):
def get(self, request):
posts = Post.objects.all()
return render(request, 'post_list.html', {'posts': posts})
def post(self, request):
title = request.POST.get('title')
content = request.POST.get('content')
post = Post.objects.create(title=title, content=content)
return JsonResponse({'id': post.id})
# Встроенный ListView (автоматически)
class PostListView(ListView):
model = Post
template_name = 'post_list.html' # по умолчанию: post_list.html
context_object_name = 'posts' # по умолчанию: object_list
paginate_by = 10
def get_queryset(self):
return Post.objects.filter(published=True)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['title'] = 'All Posts'
return context
# DetailView для одного объекта
class PostDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
context_object_name = 'post'
pk_url_kwarg = 'post_id' # параметр из URL
# CreateView для создания
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'content']
template_name = 'post_form.html'
success_url = reverse_lazy('post_list')
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
# UpdateView для редактирования
class PostUpdateView(LoginRequiredMixin, UpdateView):
model = Post
fields = ['title', 'content']
template_name = 'post_form.html'
pk_url_kwarg = 'post_id'
success_url = reverse_lazy('post_list')
# DeleteView для удаления
class PostDeleteView(LoginRequiredMixin, DeleteView):
model = Post
pk_url_kwarg = 'post_id'
success_url = reverse_lazy('post_list')
3. Миксины (Mixins) для переиспользования логики
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
from django.http import Http404
# Кастомный миксин для проверки владельца
class OwnerRequiredMixin(LoginRequiredMixin):
"""Проверяет, что пользователь — владелец объекта"""
def get_object(self, queryset=None):
obj = super().get_object(queryset)
if obj.author != self.request.user:
raise Http404("You don't own this post")
return obj
# Миксин для логирования доступа
class LogAccessMixin:
"""Логирует доступ к view"""
def get(self, request, *args, **kwargs):
print(f"User {request.user} accessed {self.__class__.__name__}")
return super().get(request, *args, **kwargs)
# Комбинирование миксинов
class MyProtectedView(OwnerRequiredMixin, LogAccessMixin, DetailView):
model = Post
template_name = 'post_detail.html'
4. API Views с JSON
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
import json
# Декоратор для ограничения методов
@require_http_methods(["GET", "POST"])
def api_posts(request):
if request.method == 'GET':
posts = Post.objects.values('id', 'title')
return JsonResponse({'data': list(posts)})
elif request.method == 'POST':
try:
data = json.loads(request.body)
post = Post.objects.create(
title=data['title'],
content=data['content']
)
return JsonResponse({
'id': post.id,
'message': 'Created'
}, status=201)
except json.JSONDecodeError:
return JsonResponse({'error': 'Invalid JSON'}, status=400)
# REST API view
from django.shortcuts import get_object_or_404
@require_http_methods(["GET", "PUT", "DELETE"])
def api_post_detail(request, post_id):
post = get_object_or_404(Post, id=post_id)
if request.method == 'GET':
return JsonResponse({
'id': post.id,
'title': post.title,
'content': post.content
})
elif request.method == 'PUT':
data = json.loads(request.body)
post.title = data.get('title', post.title)
post.content = data.get('content', post.content)
post.save()
return JsonResponse({'message': 'Updated'})
elif request.method == 'DELETE':
post.delete()
return JsonResponse({'message': 'Deleted'}, status=204)
5. Обработка формм
from django import forms
from django.shortcuts import render, redirect
from myapp.models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'content']
def post_create(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.instance.author = request.user
form.save()
return redirect('post_list')
else:
form = PostForm()
return render(request, 'post_form.html', {'form': form})
6. Request и Response объекты
from django.http import HttpResponse, JsonResponse, FileResponse
from django.shortcuts import render
def request_info(request):
# Информация о request
method = request.method # GET, POST, PUT и т.д.
path = request.path # /posts/
user = request.user # Текущий пользователь
# GET параметры
page = request.GET.get('page', 1)
search = request.GET.get('search', '')
# POST данные
if request.method == 'POST':
title = request.POST.get('title')
content = request.POST.get('content')
# JSON data
if request.content_type == 'application/json':
import json
data = json.loads(request.body)
# Headers
user_agent = request.META.get('HTTP_USER_AGENT')
# Различные responses
return render(request, 'template.html') # HTML
return JsonResponse({'status': 'ok'}) # JSON
return HttpResponse("Text") # Plain text
return FileResponse(open('file.pdf')) # File download
7. Middleware и декораторы для views
from django.utils.decorators import decorator_from_middleware
from django.http import HttpResponseForbidden
from functools import wraps
# Кастомный декоратор
def admin_only(view_func):
@wraps(view_func)
def wrapper(request, *args, **kwargs):
if not request.user.is_staff:
return HttpResponseForbidden("Admin only")
return view_func(request, *args, **kwargs)
return wrapper
@admin_only
def admin_panel(request):
return render(request, 'admin.html')
# Встроенные декораторы
from django.views.decorators.cache import cache_page
from django.views.decorators.csrf import csrf_exempt
@cache_page(60 * 5) # Кэш на 5 минут
def cached_view(request):
return render(request, 'expensive.html')
@csrf_exempt # Отключить CSRF проверку (будьте осторожны!)
def webhook_view(request):
return JsonResponse({'status': 'ok'})
8. Асинхронные views (Django 3.1+)
from django.views import View
from django.views.decorators.http import require_http_methods
import asyncio
# Асинхронная функция-view
async def async_posts(request):
posts = await sync_to_async(Post.objects.all)()
context = {'posts': posts}
return render(request, 'posts.html', context)
# Асинхронный класс-view
class AsyncPostListView(View):
async def get(self, request):
from django.db.models import Count
from asgiref.sync import sync_to_async
posts = await sync_to_async(list)(Post.objects.all())
return render(request, 'posts.html', {'posts': posts})
9. Обработка ошибок в views
from django.http import HttpResponseNotFound, HttpResponseServerError
from django.core.exceptions import PermissionDenied
def safe_view(request, post_id):
try:
post = Post.objects.get(id=post_id)
except Post.DoesNotExist:
return HttpResponseNotFound("Post not found")
if not post.is_published and post.author != request.user:
raise PermissionDenied("You can't access this post")
try:
# Опасная операция
data = expensive_operation(post)
except Exception as e:
return HttpResponseServerError(f"Error: {e}")
return render(request, 'post_detail.html', {'post': post, 'data': data})
10. URLs и routing
# urls.py
from django.urls import path
from . import views
urlpatterns = [
# FBV
path('posts/', views.post_list, name='post_list'),
path('posts/<int:post_id>/', views.post_detail, name='post_detail'),
# CBV
path('posts/', views.PostListView.as_view(), name='post_list'),
path('posts/<int:pk>/', views.PostDetailView.as_view(), name='post_detail'),
path('posts/create/', views.PostCreateView.as_view(), name='post_create'),
path('posts/<int:pk>/edit/', views.PostUpdateView.as_view(), name='post_edit'),
path('posts/<int:pk>/delete/', views.PostDeleteView.as_view(), name='post_delete'),
# API
path('api/posts/', views.api_posts, name='api_posts'),
path('api/posts/<int:post_id>/', views.api_post_detail, name='api_post_detail'),
]
Best Practices
# ✓ Хорошо: Logic в views, templates для рендеринга
def post_list(request):
posts = Post.objects.filter(published=True)
return render(request, 'post_list.html', {'posts': posts})
# ✗ Плохо: HTML в view
def post_list(request):
posts = Post.objects.all()
html = f"<h1>Posts: {len(posts)}</h1>"
return HttpResponse(html)
# ✓ Хорошо: Используй get_object_or_404
post = get_object_or_404(Post, id=post_id)
# ✗ Плохо: Обработка исключения вручную
try:
post = Post.objects.get(id=post_id)
except Post.DoesNotExist:
return "Not found"
# ✓ Хорошо: Миксины для переиспользования
class MyProtectedView(LoginRequiredMixin, DetailView):
pass
Заключение
Django views — это сердце приложения, где обрабатывается бизнес-логика. Выбор между FBV и CBV зависит от сложности: для простого кода — функции, для сложного с переиспользованием — классы и миксины. Главное — разделение ответственности: views получают данные из моделей, рендерят шаблоны, и возвращают responses пользователю.