Django для веб-разработки: практическое введение с примерами кода
Основы Django: создание первого проекта
Как создать проект Django с нуля?
Наиболее эффективный способ начать работу с Django - использовать виртуальное окружение и стандартный инструментарий. Рассмотрим пошаговую инструкцию.
Установка виртуального окружения и Django:
python -m venv venv
source venv/bin/activate # Linux/macOS
venv\Scripts\activate # Windows
pip install djangoфреймворк python django (фреймворк django в python)
Создание проекта mysite:
django-admin startproject mysite
cd mysitePython manage py (manage.py в django)
Создание приложения blog:
python manage.py startapp blog
Python run manage py (запуск manage.py в django)
Добавим приложение в settings.py (INSTALLED_APPS).
Определим простую модель в blog/models.py:
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.titlePython manage py migrate (команда migrate в django)
Создадим миграции и применим их:
python manage.py makemigrations
python manage.py migrateЗарегистрируем модель в админке (blog/admin.py):
from django.contrib import admin
from .models import Post
admin.site.register(Post)Создадим суперпользователя:
python manage.py createsuperuserЗапускаем сервер:
python manage.py runserverОткрываем http://127.0.0.1:8000/admin/ и проверяем работу.
Типичная проблема: ModuleNotFoundError: No module named 'django'. Возникает, если Django не установлен в активном виртуальном окружении. Решение: активировать виртуальное окружение и выполнить pip install django.
Другая проблема: при попытке применить миграции возникает django.db.utils.OperationalError: no such table. Это случается, если база данных SQLite повреждена или удалена. Решение: удалить файл db.sqlite3 и снова выполнить migrate.
Как использовать шаблон cookiecutter для ускорения старта?
Вместо ручного создания проекта можно применить cookiecutter-django. Это шаблон, включающий типовую структуру, настройки Docker, PostgreSQL, тестирование и т.д.
pip install cookiecutter
cookiecutter https://github.com/cookiecutter/cookiecutter-djangoПосле задания параметров получаем готовый проект с виртуальным окружением, настроенными статическими файлами, медиа, конфигурацией базы данных.
Проблема: при использовании cookiecutter может возникнуть конфликт имен, если проект уже существует. Решение: указать уникальное имя проекта при генерации.
Ошибка: TemplateNotFound из-за отсутствия интернета. Необходимо убедиться в доступности репозитория GitHub.
Как настроить Docker для разработки Django?
Использование Docker упрощает развертывание и изоляцию окружения. Пример простого Dockerfile:
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]Файл docker-compose.yml для связки с PostgreSQL:
version: '3'
services:
db:
image: postgres:15
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
web:
build: .
ports:
- "8000:8000"
depends_on:
- dbПроблема: при запуске контейнера не удается подключиться к базе данных из-за неправильного хоста (localhost). Решение: в settings.py указать 'HOST': 'db' (имя сервиса).
Расширенные примеры работы с Django
Работа с формами и валидация
Создадим форму обратной связи с использованием ModelForm и обработаем её в представлении.
Файл forms.py приложения blog:
from django import forms
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'content']
widgets = {
'content': forms.Textarea(attrs={'rows': 5}),
}Представление views.py:
from django.shortcuts import render, redirect
from .forms import PostForm
def create_post(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.save()
return redirect('post_list')
else:
form = PostForm()
return render(request, 'blog/post_form.html', {'form': form})Шаблон templates/blog/post_form.html:
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Сохранить</button>
</form>Результат: при отправке формы данные проходят валидацию, сохраняются в базу, и происходит перенаправление.
Использование generic-представлений 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'
class PostDetailView(DetailView):
model = Post
template_name = 'blog/post_detail.html'URL-паттерны (urls.py):
from django.urls import path
from .views import PostListView, PostDetailView
urlpatterns = [
path('', PostListView.as_view(), name='post_list'),
path('<int:pk>/', PostDetailView.as_view(), name='post_detail'),
]Шаблон списка:
{% for post in posts %}
<h2><a href="{% url 'post_detail' post.pk %}">{{ post.title }}</a></h2>
<p>{{ post.content|truncatewords:20 }}</p>
{% endfor %}Результат: список постов с ссылками, страница детального просмотра.
Добавление пагинации
В ListView пагинация настраивается очень просто:
class PostListView(ListView):
model = Post
paginate_by = 5
# остальные атрибутыВ шаблоне:
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
<a href="?page=1">« первая</a>
<a href="?page={{ page_obj.previous_page_number }}">предыдущая</a>
{% endif %}
<span class="current">Страница {{ page_obj.number }} из {{ page_obj.paginator.num_pages }}.</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">следующая</a>
<a href="?page={{ page_obj.paginator.num_pages }}">последняя »</a>
{% endif %}
</span>
</div>Результат: на странице отображается не более 5 записей, внизу появляются ссылки для навигации.
REST API с Django REST Framework
Установка: pip install djangorestframework. Добавляем 'rest_framework' в INSTALLED_APPS. Создаём сериализатор:
from rest_framework import serializers
from .models import Post
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = '__all__'Представление (views.py):
from rest_framework import generics
from .models import Post
from .serializers import PostSerializer
class PostListAPI(generics.ListCreateAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializer
class PostDetailAPI(generics.RetrieveUpdateDestroyAPIView):
queryset = Post.objects.all()
serializer_class = PostSerializerURL-паттерны:
from django.urls import path
from .views import PostListAPI, PostDetailAPI
urlpatterns = [
path('api/posts/', PostListAPI.as_view(), name='post-list'),
path('api/posts/<int:pk>/', PostDetailAPI.as_view(), name='post-detail'),
]Результат: полноценный REST API для модели Post с поддержкой GET, POST, PUT, PATCH, DELETE.
Использование сигналов для автоматических действий
Например, при создании поста автоматически генерировать slug. В signals.py:
from django.db.models.signals import pre_save
from django.dispatch import receiver
from django.utils.text import slugify
from .models import Post
@receiver(pre_save, sender=Post)
def create_slug(sender, instance, **kwargs):
if not instance.slug:
instance.slug = slugify(instance.title)В apps.py приложения нужно импортировать сигналы:
from django.apps import AppConfig
class BlogConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'blog'
def ready(self):
import blog.signalsРезультат: при сохранении поста slug заполняется автоматически из заголовка.