Практикум — доска объявлений на Django
Зачем этот практикум
Первая программа даёт один приложение и одну модель. Справочник разбирает инструменты по отдельности. Здесь — цельный сайт: каталог объявлений с рубриками, комментариями и разграничением доступа — типичный учебный проект уровня «доска объявлений».
Перед стартом: завершите 3011, просмотрите в 301 разделы про CBV, formsets, auth и (по желанию) PostgreSQL.
Что получится
| Функция | Реализация |
|---|---|
| Главная, навигация | Приложение main, базовый шаблон |
| Рубрики | Модель Rubric, список и фильтр объявлений |
| Объявления | Модель Listing, CRUD через CBV + формы |
| Комментарии | Связь FK, inline в админке, форма на странице объявления |
| Пользователи | django.contrib.auth, только автор правит своё |
| API (опционально) | DRF или JsonResponse из 301 |
Структура проекта
Рекомендуемое разбиение на приложения (каждое — одна зона ответственности):
board_project/
manage.py
board_project/ # пакет конфигурации
settings.py
urls.py
main/ # главная, layout, статика
catalog/ # Rubric, Listing
comments/ # Comment
accounts/ # профиль, регистрация (опционально)
templates/layout/
static/
В INSTALLED_APPS подключают main, catalog, comments, accounts и стандартные contrib.*.
Модели предметной области
# catalog/models.py
from django.conf import settings
from django.db import models
from django.urls import reverse
class Rubric(models.Model):
name = models.CharField('Название', max_length=80)
slug = models.SlugField(unique=True)
order = models.PositiveSmallIntegerField(default=0)
class Meta:
ordering = ['order', 'name']
verbose_name = 'рубрика'
verbose_name_plural = 'рубрики'
def __str__(self):
return self.name
class Listing(models.Model):
rubric = models.ForeignKey(Rubric, on_delete=models.PROTECT, related_name='listings')
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='listings',
)
title = models.CharField(max_length=120)
content = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_at']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('catalog:listing_detail', kwargs={'pk': self.pk})
# comments/models.py
class Comment(models.Model):
listing = models.ForeignKey(
'catalog.Listing',
on_delete=models.CASCADE,
related_name='comments',
)
author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
text = models.TextField(max_length=2000)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['created_at']
PROTECT у рубрики не даёт удалить рубрику, пока в ней есть объявления. get_absolute_url нужен для редиректов после сохранения и ссылок в админке.
Представления и маршруты
Именованное пространство app_name = 'catalog' в catalog/urls.py:
| URL | View | Назначение |
|---|---|---|
/ | TemplateView / главная main | вход |
/catalog/ | ListingListView | все опубликованные |
/catalog/rubric/<slug>/ | список с фильтром rubric__slug | объявления рубрики |
/catalog/<pk>/ | ListingDetailView | карточка + комментарии |
/catalog/add/ | LoginRequiredMixin + CreateView | новое объявление |
/catalog/<pk>/edit/ | UpdateView, проверка авторства | правка |
Фильтр только опубликованных записей:
class ListingListView(ListView):
model = Listing
template_name = 'catalog/listing_list.html'
context_object_name = 'listings'
paginate_by = 10
def get_queryset(self):
qs = Listing.objects.filter(published=True).select_related('rubric', 'author')
slug = self.kwargs.get('slug')
if slug:
qs = qs.filter(rubric__slug=slug)
return qs
Правка чужого объявления закрывают переопределением get_queryset в UpdateView или mixin, сравнивающим obj.author_id с request.user.id.
Комментарии на странице объявления
В DetailView в get_context_data добавляют форму комментария. POST обрабатывают в post() того же класса или отдельным FBV:
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['text']
После form.save(commit=False) выставляют author=request.user и listing_id из URL. Редирект — на get_absolute_url() объявления.
Административный сайт
@admin.register(Listing)
class ListingAdmin(admin.ModelAdmin):
list_display = ('title', 'rubric', 'price', 'published', 'created_at')
list_filter = ('published', 'rubric')
list_editable = ('published',)
search_fields = ('title', 'content')
date_hierarchy = 'created_at'
autocomplete_fields = ('author',)
Для комментариев — TabularInline на странице объявления. Подробнее — справочник, §8.
Пользователи и права
createsuperuser— модерация через/admin/.- Регистрация —
django.contrib.authviews или формаUserCreationFormвaccounts. - Публикация объявления: флаг
published=Falseпо умолчанию; модератор включает в админке или автор с правомcatalog.can_publish_listing(кастомноеPermissionвMetaмодели).
Цепочка входа и сброса пароля — готовые CBV в 301, §14.
Шаблоны и статика
Базовый шаблон templates/layout/base.html с блоками title, content, навигацией по рубрикам (Rubric.objects.all() в context processor или в каждом view). Статика — {% load static %}, в продакшене — collectstatic.
Оформление через Bootstrap (django-bootstrap5 и аналоги) опционально: подключают в INSTALLED_APPS и наследуют их теги в layout.
База данных
Для разработки достаточно SQLite. Для полнотекстового поиска и сложных ограничений — PostgreSQL (см. 301, PostgreSQL). В settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('PGDATABASE', 'board'),
'USER': os.environ.get('PGUSER', 'board'),
'PASSWORD': os.environ.get('PGPASSWORD', ''),
'HOST': os.environ.get('PGHOST', 'localhost'),
'PORT': os.environ.get('PGPORT', '5432'),
}
}
REST для того же проекта
После HTML-версии те же модели подключают к DRF: ListingSerializer, ListingViewSet, router на /api/listings/. Отдельный фронтенд (React, Angular) ходит на API; сессионная auth или JWT — в 3012.
Минимальный вариант без DRF описан в 3012.
Порядок внедрения (чек-лист)
- Проект и приложения,
migrate, суперпользователь. - Модели
Rubric,Listing, миграции, фикстуры рубрик (fixturesилиloaddata). - Админка, несколько тестовых объявлений.
ListView/DetailView, шаблоны, пагинация.CreateView/UpdateViewсLoginRequiredMixin.- Комментарии и форма на детальной странице.
- Фильтр по рубрике, главная с навигацией.
- Тесты: список 200, создание только для авторизованных.
- (Опционально) DRF или деплой — 30.md, 301 §16.
Дальше
См. также
Другие статьи этого же раздела в боковом меню (как на странице "О разделе"). Python как язык общего назначения - философия, ключевые свойства и области применения в современной разработке. Python — это высокоуровневый язык программирования общего назначения, который отличается читаемым синтаксисом и широким спектром применения. Принципы, которые делают код понятным, поддерживаемым и расширяемым. Примеры реализации типовых приложений. Каждый пример сопровождается разбором ключевых концепций языка. Наверняка каждый новичок, решивший перейти в что-то стандартное в Python, открывает себе этот файл. Как устроен Python, что входит в комплект и какие есть реализации. Структурные каркасы для построения приложений, как они устроены. Фреймворки, библиотеки, инструменты сборки, среды выполнения, системы тестирования и специализированные платформы, объединённые общей философией ясности, простоты и гибкости. Что такое модули, как устроены механизмы импорта и загрузки. Управление изолированной средой и зависимостями проекта. История Python - ключевые этапы развития языка, сообщества и экосистемы инструментов. Философия Python не зафиксирована в официальных стандартах, но она глубоко интегрирована в язык, его стандартную библиотеку, документацию и культуру разработчиков.Python - язык общего назначения
Что требуется знать перед началом изучения языка программирования Python
Рекомендации по разработке на Python
Простые приложения на Python
Встроенный модуль builtins и типизация в Python
Архитектура интерпретатора Python
Фреймворки и библиотеки Python
Экосистема Python-приложений
Модули в Python
Виртуальные окружения и управление зависимостями
История языка Python
Философия Python - Zen of Python