Django веб-фреймворк: практическое руководство по созданию сайтов
Основные этапы разработки веб-приложения на Django
Рассмотрим процесс создания простого блога на Django. Сначала выполняется установка фреймворка и создание проекта.
Наиболее распространенный подход включает следующие шаги:
- Установка Django и создание виртуального окружения.
- Создание проекта командой
django-admin startproject mysite. - Создание приложения
python manage.py startapp blog. - Определение модели
Postвmodels.py. - Регистрация приложения в
settings.pyи выполнение миграций. - Создание представлений (views) и маршрутов (urls).
- Создание шаблонов для отображения.
- Запуск сервера разработки.
Пример модели Post:
from django.db import models
from django.utils import timezone
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.title
Django разработка веб приложений на python (разработка веб-приложений на django)
Далее в файле views.py создаются функции для отображения списка и детальной страницы:
from django.shortcuts import render, get_object_or_404
from .models import Post
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'blog/post_list.html', {'posts': posts})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
Fast api python (fastapi для python)
Маршруты в urls.py приложения:
from django.urls import path
from . import views
urlpatterns = [
path('', views.post_list, name='post_list'),
path('post/<int:pk>/', views.post_detail, name='post_detail'),
]
веб библиотека python (веб-библиотека python (фреймворк))
Шаблоны используют переменные из контекста. Пример post_list.html:
<ul>
{% for post in posts %}
<li>
<a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a>
<p>{{ post.published_date }}</p>
</li>
{% endfor %}
</ul>
Flask на языке python (flask на python)
Типичные ошибки:
- Забыли добавить приложение в
INSTALLED_APPS- получается ошибкаdjango.core.exceptions.ImproperlyConfigured. - Не выполнили миграции - модель не создается в базе.
- Ошибка в имени шаблона -
TemplateDoesNotExist. - Неправильный импорт -
ImportErrorпри обращении к модели.
Как сделать код представлений более кратким и переиспользуемым?
Вместо функций можно использовать встроенные class-based views (CBV). Для списка - ListView, для деталей - DetailView.
from django.views.generic import ListView, DetailView
from .models import Post
class PostListView(ListView):
model = Post
template_name = 'blog/post_list.html'
context_object_name = 'posts'
queryset = Post.objects.filter(published_date__lte=timezone.now()).order_by('-published_date')
class PostDetailView(DetailView):
model = Post
template_name = 'blog/post_detail.html'
Python manage py runserver (запуск сервера разработки django через manage.py runserver)
Маршруты обновляются:
from django.urls import path
from .views import PostListView, PostDetailView
urlpatterns = [
path('', PostListView.as_view(), name='post_list'),
path('post/<int:pk>/', PostDetailView.as_view(), name='post_detail'),
]
Проблемы CBV: легко забыть указать template_name или context_object_name, что приведет к использованию значений по умолчанию. Также требуется импортировать timezone для фильтрации.
Как создать REST API для внешних клиентов?
Для построения API используется Django REST Framework. Установка: pip install djangorestframework. Затем создаются сериализаторы и viewsets.
# serializers.py
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['id', 'title', 'content', 'published_date']
# views.py (rest)
from rest_framework import viewsets
from .models import Post
from .serializers import PostSerializer
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.all()
serializer_class = PostSerializer
Маршруты подключаются через DefaultRouter:
# urls.py (основной)
from rest_framework.routers import DefaultRouter
from blog.views import PostViewSet
router = DefaultRouter()
router.register(r'posts', PostViewSet)
urlpatterns += router.urls
После запуска сервера API доступно по адресам /posts/ (GET, POST) и /posts/{id}/ (GET, PUT, DELETE).
Типичная ошибка: отсутствие разрешений может привести к тому, что любой пользователь сможет изменять данные. Рекомендуется добавить permission_classes.
Как вынести часто используемые запросы из представлений?
Кастомный менеджер модели позволяет инкапсулировать запросы. Например, чтобы получать только опубликованные посты.
from django.db import models
from django.utils import timezone
class PublishedManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(published_date__lte=timezone.now())
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published_date = models.DateTimeField(default=timezone.now)
objects = models.Manager() # стандартный
published = PublishedManager() # кастомный
Теперь Post.published.all() возвращает только опубликованные посты. Это упрощает представления и повышает читаемость.
Проблема: если забыть вернуть стандартный менеджер objects, то все запросы через Post.objects будут использовать кастомный менеджер, что может нарушить функциональность.
Расширенный пример: поиск и пагинация в блоге
Реализуем функциональность поиска по заголовкам и содержанию постов, а также постраничную навигацию.
Модель
Используем ту же модель Post, что и выше.
Представление с пагинацией и поиском
from django.shortcuts import render
from django.core.paginator import Paginator
from django.db.models import Q
from .models import Post
def post_list(request):
queryset = Post.published.all()
query = request.GET.get('q')
if query:
queryset = queryset.filter(
Q(title__icontains=query) | Q(content__icontains=query)
)
paginator = Paginator(queryset, 5) # 5 постов на странице
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return render(request, 'blog/post_list.html', {'page_obj': page_obj, 'query': query})
Шаблон с формой поиска и пагинацией
<form method='get' action='.'>
<input type='text' name='q' value='{{ query }}' placeholder='Поиск...'>
<button type='submit'>Найти</button>
</form>
<ul>
{% for post in page_obj %}
<li>
<a href='{% url 'post_detail' pk=post.pk %}'>{{ post.title }}</a>
<p>{{ post.published_date|date:'d.m.Y' }}</p>
</li>
{% endfor %}
</ul>
<div class='pagination'>
{% if page_obj.has_previous %}
<a href='?page={{ page_obj.previous_page_number }}&q={{ query }}'>Предыдущая</a>
{% endif %}
<span>Страница {{ page_obj.number }} из {{ page_obj.paginator.num_pages }}</span>
{% if page_obj.has_next %}
<a href='?page={{ page_obj.next_page_number }}&q={{ query }}'>Следующая</a>
{% endif %}
</div>
Результат
При переходе на страницу отображаются первые 5 постов. При вводе поискового запроса в строку и нажатии 'Найти' список фильтруется. Пагинация сохраняет переданный запрос через GET-параметр q. Если постов больше 5, появляются ссылки на предыдущую и следующую страницы.
Пример использования: посетитель ищет 'Python' - выводятся посты, содержащие это слово в заголовке или тексте. При этом номер страницы в URL меняется, а поисковый запрос остается.