Базовой модели, в которой будут храниться и надрубрики, и подрубрики, мы дадим имя Rubric. Ее структура приведена в таблице
Код класса модели Rubric. Не забываем, что код всех моделей заносится в модуль models.ру пакета приложения.
class Rubric (models.Model) :
name = models.CharField(max_length=20, db_index=True, unique=True, verbose_name='Название')
order = models.SmallIntegerField(default=0, db_index=True, verbose_name='Порядок')
super_rubric = models.ForeignKey('SuperRubric', on_delete=models.PROTECT, null=True, blank=True, verbose_name='Надрубрика')
Для работы С надрубриками объявим прокси-модель SuperRubric, производную от Rubric. Она будет обрабатывать только надрубрики.
Код обоих классов: И модели SuperRubric, И диспетчера записей SuperRubricManager
class SuperRubricManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(super_rubric__isnull=True)
class SuperRubric(Rubric):
objects = SuperRubricManager()
def __str__(self) :
return self.name
class Meta:
proxy = True
ordering = ('order', 'name')
verbose_name = 'Надрубрика'
verbose_name_plural = 'Надрубрики'
Условия фильтрации записей указываем в переопределенном методе get_queryset() Класса Диспетчера записей SuperRubricManager.
В самом классе модели SuperRubric задаем диспетчер записей SuperRubricManager в качестве основного.
Код классов модели subRubric и диспетчера записей SubRubricManager
class SubRubricManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(super_rubric__isnull=False)
class SubRubric(Rubric):
objects = SubRubricManager()
def __str__(self) :
return '%s - %s' % (self.super_rubric.name, self.name)
class Meta:
proxy = True
ordering = ('super_rubric__order', 'super_rubric__name', 'order', 'name')
verbose_name = 'Подрубрика'
verbose_name_plural = 'Подрубрики'
Диспетчер записей SubRubricManager будет отбирать лишь записи с непустым полем super_rubric (т.е. подрубрики).
Код классов редактора SuperRubricAdmin и встроенного редактора SubRubricinline. Не забываем, что код редакторов, равно как и код, регистрирующий модели и редакторы в подсистеме административного сайта, должен записываться в модуль admin.ру пакета приложения.
from .models import SuperRubric, SubRubric
class SubRubricinline(admin.TabularInline):
model = SubRubric
class SuperRubricAdmin (admin.ModelAdmin) :
exclude = ('super_rubric',)
inlines = (SubRubricinline,)
admin.site.register(SuperRubric, SuperRubricAdmin)
У подрубрик сделаем поле надрубрики (super rubric) обязательным для заполнения. Для этого мы объявим форму SubRubricForm в модуле forms.py пакета приложения.
from .models import SuperRubric, SubRubric
class SubRubricForm (forms.ModelForm):
super_rubric = forms.ModelChoiceField(queryset=SuperRubric.objects.all(),empty_label=None, label='Надрубрика', required=True)
class Meta:
model = SubRubric
fields = '__all__'
Мы убрали у раскрывающегося списка, с помощью которого пользователь будет выбирать подрубрику, "пустой" пункт, присвоив параметру empty_label конструктора класса поля ModelChoiceField значение None.
Код, объявляющий класс редактора SubRubricAdmin.
from .forms import SubRubricForm
class SubRubricAdmin(admin.ModelAdmin) :
form = SubRubricForm
admin.site.register(SubRubric, SubRubricAdmin)
Создадим в пакете приложения модуль middlewares.py и запишем в него код обработчика контекста bboard_context_processor()
from .models import SubRubric
def bboard_context_processor(request):
context = {}
context['rubrics'] = SubRubric.objects.all()
return context
Откроем модуль settings.py пакета конфигурации и зарегистрируем только что написанный обработчик контекста.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.dj ango.DjangoTemplates',
'OPTIONS': {
'context_processors': [
...
'main.middlewares.bboard_context_processor',
],
},
},
]
Выполним еще пару подготовительных действий. Во-первых, в модуле views.py пакета приложения объявим "пустой" контроллер-функцию by_rubric():
def by_rubric(request, pk):
pass
Во-вторых, добавим в список маршрутов уровня приложения маршрут, ведущий на этот контроллер:
from .views import by_rubric
...
urlpatterns = [
...
path('<int:pk>/', by_rubric, name='by_rubric'),
path('<str:page>/', other_page, name='other'),
...
]
Откроем шаблон layout\basic.html и исправим код вертикальной панели навигации следующим образом:
<a class="nav-link root" href="{% url 'main:index' %}">Главная</a>
{% for rubric in rubrics %}
{% ifchanged rubric.super_rubric.pk %}
<span class="nav-link root font-weight-bold">{{ rubric.super_rubric.name }}</span>
{% endifchanged %}
<a class="nav-link" href="{% url 'main:by_rubric' pk=rubric.pk %}">{{ rubric.name }}</a>
{% endfor %}
<a class="nav-link root" href="{% url 'main:other' page='about' %}">О сайте</a>