Skip to content

Conversation

@sergeikuz
Copy link
Contributor

@sergeikuz sergeikuz commented Nov 17, 2025

Issue #117: Implement blog system for /blog page

  1. Backend:

Created models: BlogPost, BlogCategory, Tag.

Implemented views: BlogListView and BlogDetailView (with InertiaJS support).

Added filtering by category (via GET parameter).

Implemented search by title and full_content (via q GET parameter).

Added pagination using Django’s Paginator (6 items per page).

Copy link

@maxjamchuk maxjamchuk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Отличная работа: блог как отдельный Django-сервис оформлен понятно (модели/админка/урлы/вьюхи/подключение). Перед мёржжем обязательно исправить замечания с CAUTION и WARNING:

CAUTION: починить BlogListView.as_view() (сейчас синтаксическая ошибка);

CAUTION: не отдавать author.email в публичный payload;

WARNING: определиться с политикой публикации (is_published).

Остальные комментарии — рекомендательные (TIP/NOTE).

from .views import BlogDetailView, BlogListView

urlpatterns = [
path("", BlogListView .as_view(), name="blog_list"),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

BlogListView .as_view() — пробел перед точкой делает выражение синтаксически невалидным в Python (будет SyntaxError). Нужно BlogListView.as_view().

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Блокирующий синтаксис → чинить до мёрджа

'is_published': post.is_published,
'duration_minutes': post.duration_minutes,
'category': post.category.name,
'author': post.author.email,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

BlogDetailView отдаётся post.author.email. Это утечка персональных данных (публичная страница блога не должна раздавать email). Лучше отдавать first_name/username/display_name.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

в списке и деталке нет фильтра по is_published а это значит, что потенциально можно показывать черновики и скрытые посты. Обычно делаем так: qs = qs.filter(is_published=True) и в detail: get_object_or_404(BlogPost, pk=pk, is_published=True).

page_obj = paginator.get_page(page_number)

posts = list(page_obj.object_list.values(
'id', 'title', 'content_short', 'content_full',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

в списке отдаётся content_full для каждого поста — это может быть жирно по трафику. Для списка обычно достаточно content_short, а content_full — только в детальном представлении.

Q(title__icontains=q) | Q(content_full__icontains=q)
)

paginator = Paginator(qs, 6)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

стоит добавить стабильную сортировку перед пагинацией (order_by('-created_at')), иначе порядок страниц может «прыгать».

'duration_minutes': post.duration_minutes,
'category': post.category.name,
'author': post.author.email,
'tags': list(post.tags.values_list('name', flat=True)),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

можно оптимизировать: select_related('category','author').prefetch_related('tags'), чтобы не ловить лишние запросы на связанных данных.

readonly_fields = ("created_at", "updated_at")

def get_tags(self, obj):
return ", ".join([tag.name for tag in obj.tags.all()])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

get_tags сейчас делает obj.tags.all() и собирает имена. На списке админки это может дать проблему N+1. Опционально: переопределить get_queryset() и сделать prefetch_related('tags'), а в get_tags использовать values_list.

class BlogPostAdmin(admin.ModelAdmin):
list_display = ("id", "title", "author", "category", "created_at",
"is_published")
list_filter = ("author", "category", "title", "tags")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

list_filter = ("author", "category", "title", "tags") — фильтрация по заголовку ("title") часто не очень полезна и может раздувать список значений; обычно title отправляем в search_fields.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants