Добавил правильные хлебные крошки
This commit is contained in:
parent
c65be53032
commit
61c7af35c1
@ -1,4 +1,4 @@
|
|||||||
from programmer.mixins import MenuContextMixin
|
from programmer.mixins import MenuContextMixin, BreadcrumbMixin
|
||||||
from django.views.generic import ListView, DetailView, CreateView
|
from django.views.generic import ListView, DetailView, CreateView
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
@ -15,13 +15,22 @@ from django.shortcuts import redirect
|
|||||||
from django.contrib.admin.views.decorators import staff_member_required
|
from django.contrib.admin.views.decorators import staff_member_required
|
||||||
|
|
||||||
|
|
||||||
class ArticleListView(MenuContextMixin, ListView):
|
class ArticleListView(MenuContextMixin, BreadcrumbMixin, ListView):
|
||||||
"""Список статей"""
|
"""Список статей"""
|
||||||
model = Article
|
model = Article
|
||||||
template_name = 'blog/article_list.html'
|
template_name = 'blog/article_list.html'
|
||||||
context_object_name = 'articles'
|
context_object_name = 'articles'
|
||||||
paginate_by = 10
|
paginate_by = 10
|
||||||
|
|
||||||
|
def get_breadcrumbs(self):
|
||||||
|
if 'category_slug' in self.kwargs:
|
||||||
|
category = Category.objects.get(slug=self.kwargs['category_slug'])
|
||||||
|
return [
|
||||||
|
{'title': 'Статьи', 'url_name': 'blog:article_list'},
|
||||||
|
{'title': category.name, 'url_name': None},
|
||||||
|
]
|
||||||
|
return [{'title': 'Статьи', 'url_name': None}]
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
category_slug = self.kwargs.get('category_slug')
|
category_slug = self.kwargs.get('category_slug')
|
||||||
return get_published_articles(category_slug)
|
return get_published_articles(category_slug)
|
||||||
@ -51,13 +60,26 @@ class ArticleListView(MenuContextMixin, ListView):
|
|||||||
return super().dispatch(*args, **kwargs)
|
return super().dispatch(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ArticleDetailView(MenuContextMixin, DetailView, CreateView):
|
class ArticleDetailView(MenuContextMixin, BreadcrumbMixin, DetailView, CreateView):
|
||||||
"""Детальная страница статьи + форма комментария"""
|
"""Детальная страница статьи + форма комментария"""
|
||||||
model = Article
|
model = Article
|
||||||
template_name = 'blog/article_detail.html'
|
template_name = 'blog/article_detail.html'
|
||||||
context_object_name = 'article'
|
context_object_name = 'article'
|
||||||
form_class = CommentForm
|
form_class = CommentForm
|
||||||
|
|
||||||
|
def get_breadcrumbs(self):
|
||||||
|
article = self.get_object()
|
||||||
|
return [
|
||||||
|
{'title': 'Статьи', 'url_name': 'blog:article_list'},
|
||||||
|
{
|
||||||
|
'title': article.category.name,
|
||||||
|
'url_name': 'blog:category_detail',
|
||||||
|
'category_slug': article.category.slug,
|
||||||
|
# 'url_args': [article.category.slug]
|
||||||
|
},
|
||||||
|
{'title': article.title, 'url_name': None},
|
||||||
|
]
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
article = get_article_by_slug(self.kwargs['slug'])
|
article = get_article_by_slug(self.kwargs['slug'])
|
||||||
if article is None:
|
if article is None:
|
||||||
@ -110,7 +132,7 @@ class ArticleDetailView(MenuContextMixin, DetailView, CreateView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
context.update({
|
context.update({
|
||||||
'title': "Статии | Инструкции",
|
'title': "Статьи | Инструкции",
|
||||||
'meta_description': (
|
'meta_description': (
|
||||||
"Инструкции по работе в 1С и бизнес-решения"
|
"Инструкции по работе в 1С и бизнес-решения"
|
||||||
"инструкции, статьи помощь 1С."
|
"инструкции, статьи помощь 1С."
|
||||||
|
|||||||
@ -48,3 +48,26 @@ class MenuContextMixin(ContextMixin):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
class BreadcrumbMixin(ContextMixin):
|
||||||
|
"""
|
||||||
|
Миксин для добавления хлебных крошек в контекст.
|
||||||
|
В дочерних классах нужно определить метод get_breadcrumbs().
|
||||||
|
"""
|
||||||
|
breadcrumbs = None
|
||||||
|
|
||||||
|
def get_breadcrumbs(self):
|
||||||
|
"""
|
||||||
|
Должен возвращать список словарей:
|
||||||
|
[{'title': 'Название', 'url_name': 'url_name', 'url_args': [...], 'url_kwargs': {...}}, ...]
|
||||||
|
Последний элемент без url_name (текущая страница).
|
||||||
|
"""
|
||||||
|
if self.breadcrumbs is not None:
|
||||||
|
return self.breadcrumbs
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_context_data(self, **kwargs):
|
||||||
|
context = super().get_context_data(**kwargs)
|
||||||
|
context['breadcrumbs'] = self.get_breadcrumbs()
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -566,10 +566,26 @@
|
|||||||
<section class="content">
|
<section class="content">
|
||||||
<!-- Breadcrumbs -->
|
<!-- Breadcrumbs -->
|
||||||
{% block breadcrumbs %}
|
{% block breadcrumbs %}
|
||||||
<nav class="breadcrumbs">
|
<nav class="breadcrumbs" aria-label="breadcrumb">
|
||||||
<a href="{% url 'home' %}" class="breadcrumb-link">Главная</a>
|
<a href="{% url 'home' %}" class="breadcrumb-link">Главная</a>
|
||||||
|
{% for crumb in breadcrumbs %}
|
||||||
<span class="breadcrumb-separator">/</span>
|
<span class="breadcrumb-separator">/</span>
|
||||||
<span class="breadcrumb-current">{{title}}</span>
|
{% if crumb.url_name %}
|
||||||
|
{% if crumb.category_slug %}
|
||||||
|
<a href="{% url crumb.url_name category_slug=crumb.category_slug %}" class="breadcrumb-link">{{ crumb.title }}</a>
|
||||||
|
{% elif crumb.url_args %}
|
||||||
|
<a href="{% url crumb.url_name crumb.url_kwargs %}" class="breadcrumb-link">{{ crumb.title }}</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{% url crumb.url_name %}" class="breadcrumb-link">{{ crumb.title }}</a>
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<span class="breadcrumb-current">{{ crumb.title }}</span>
|
||||||
|
{% endif %}
|
||||||
|
{% empty %}
|
||||||
|
{# Если крошек нет, показываем просто заголовок страницы #}
|
||||||
|
<span class="breadcrumb-separator">/</span>
|
||||||
|
<span class="breadcrumb-current">{{ title }}</span>
|
||||||
|
{% endfor %}
|
||||||
</nav>
|
</nav>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ from django.db.models import Count, QuerySet
|
|||||||
from django.contrib.auth.decorators import login_required, user_passes_test
|
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||||
from django.views.decorators.http import require_GET, require_POST
|
from django.views.decorators.http import require_GET, require_POST
|
||||||
from django.views.generic import TemplateView, ListView, CreateView, UpdateView
|
from django.views.generic import TemplateView, ListView, CreateView, UpdateView
|
||||||
from .mixins import PageViewTrackingMixin, MenuContextMixin
|
from .mixins import PageViewTrackingMixin, MenuContextMixin, BreadcrumbMixin
|
||||||
from .services import get_published_queryset, track_page_view
|
from .services import get_published_queryset, track_page_view
|
||||||
from typing import Any, Dict, Type
|
from typing import Any, Dict, Type
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
@ -95,10 +95,13 @@ class HomePageView(BasePageView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class AboutPageView(BasePageView):
|
class AboutPageView(BasePageView, BreadcrumbMixin):
|
||||||
"""Страница 'О себе'."""
|
"""Страница 'О себе'."""
|
||||||
template_name = 'programmer/about.html'
|
template_name = 'programmer/about.html'
|
||||||
|
|
||||||
|
def get_breadcrumbs(self):
|
||||||
|
return [{'title': 'Обо мне', 'url_name': None}]
|
||||||
|
|
||||||
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
|
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
@ -116,7 +119,7 @@ class AboutPageView(BasePageView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class SolutionListView(BaseListView):
|
class SolutionListView(BaseListView, BreadcrumbMixin):
|
||||||
"""Список проектов с пагинацией."""
|
"""Список проектов с пагинацией."""
|
||||||
model = Solution
|
model = Solution
|
||||||
template_name = 'programmer/solution.html'
|
template_name = 'programmer/solution.html'
|
||||||
@ -125,6 +128,9 @@ class SolutionListView(BaseListView):
|
|||||||
cards_template = 'programmer/includes/project_cards.html'
|
cards_template = 'programmer/includes/project_cards.html'
|
||||||
ordering = ['-time_create']
|
ordering = ['-time_create']
|
||||||
|
|
||||||
|
def get_breadcrumbs(self):
|
||||||
|
return [{'title': 'Проекты', 'url_name': None}]
|
||||||
|
|
||||||
def get_queryset(self) -> QuerySet:
|
def get_queryset(self) -> QuerySet:
|
||||||
"""Возвращает только опубликованные проекты."""
|
"""Возвращает только опубликованные проекты."""
|
||||||
return get_published_queryset(self.model, order_by='-time_create')
|
return get_published_queryset(self.model, order_by='-time_create')
|
||||||
@ -146,7 +152,7 @@ class SolutionListView(BaseListView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class RecallListView(BaseListView):
|
class RecallListView(BaseListView, BreadcrumbMixin):
|
||||||
"""Список отзывов с пагинацией."""
|
"""Список отзывов с пагинацией."""
|
||||||
model = Recall
|
model = Recall
|
||||||
template_name = 'programmer/recall.html'
|
template_name = 'programmer/recall.html'
|
||||||
@ -154,6 +160,9 @@ class RecallListView(BaseListView):
|
|||||||
paginate_by = 5
|
paginate_by = 5
|
||||||
ordering = ['-time_create']
|
ordering = ['-time_create']
|
||||||
|
|
||||||
|
def get_breadcrumbs(self):
|
||||||
|
return [{'title': 'Отзывы', 'url_name': None}]
|
||||||
|
|
||||||
def get_queryset(self) -> QuerySet:
|
def get_queryset(self) -> QuerySet:
|
||||||
"""Возвращает только опубликованные отзывы."""
|
"""Возвращает только опубликованные отзывы."""
|
||||||
return get_published_queryset(self.model, order_by='-time_create')
|
return get_published_queryset(self.model, order_by='-time_create')
|
||||||
@ -175,17 +184,23 @@ class RecallListView(BaseListView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class ProfileView(LoginRequiredMixin, PageViewTrackingMixin, MenuContextMixin, TemplateView):
|
class ProfileView(LoginRequiredMixin, PageViewTrackingMixin, MenuContextMixin, BreadcrumbMixin, TemplateView):
|
||||||
template_name = 'programmer/profile.html'
|
template_name = 'programmer/profile.html'
|
||||||
|
|
||||||
|
def get_breadcrumbs(self):
|
||||||
|
return [{'title': 'Профиль', 'url_name': None}]
|
||||||
|
|
||||||
class RegisterView(PageViewTrackingMixin, MenuContextMixin, SuccessMessageMixin, CreateView):
|
|
||||||
|
class RegisterView(PageViewTrackingMixin, MenuContextMixin, SuccessMessageMixin, BreadcrumbMixin, CreateView):
|
||||||
"""Регистрация нового пользователя"""
|
"""Регистрация нового пользователя"""
|
||||||
template_name = 'programmer/register.html'
|
template_name = 'programmer/register.html'
|
||||||
form_class = RegistrationForm
|
form_class = RegistrationForm
|
||||||
# success_url = reverse_lazy('profile')
|
# success_url = reverse_lazy('profile')
|
||||||
success_message = '✅ Регистрация успешна!'
|
success_message = '✅ Регистрация успешна!'
|
||||||
|
|
||||||
|
def get_breadcrumbs(self):
|
||||||
|
return [{'title': 'Регистрация', 'url_name': None}]
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
# Если есть параметр next, используем его
|
# Если есть параметр next, используем его
|
||||||
next_url = self.request.POST.get('next') or self.request.GET.get('next')
|
next_url = self.request.POST.get('next') or self.request.GET.get('next')
|
||||||
@ -207,12 +222,18 @@ class RegisterView(PageViewTrackingMixin, MenuContextMixin, SuccessMessageMixin,
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class ProfileEditView(LoginRequiredMixin, PageViewTrackingMixin, MenuContextMixin, UpdateView):
|
class ProfileEditView(LoginRequiredMixin, PageViewTrackingMixin, MenuContextMixin, BreadcrumbMixin, UpdateView):
|
||||||
model = Profile
|
model = Profile
|
||||||
form_class = ProfileForm
|
form_class = ProfileForm
|
||||||
template_name = 'programmer/profile_edit.html'
|
template_name = 'programmer/profile_edit.html'
|
||||||
success_url = reverse_lazy('profile')
|
success_url = reverse_lazy('profile')
|
||||||
|
|
||||||
|
def get_breadcrumbs(self):
|
||||||
|
return [
|
||||||
|
{'title': 'Профиль', 'url_name': 'profile'},
|
||||||
|
{'title': 'Редактирование', 'url_name': None},
|
||||||
|
]
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
# Возвращаем профиль текущего пользователя
|
# Возвращаем профиль текущего пользователя
|
||||||
return self.request.user.profile
|
return self.request.user.profile
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user