changed 4 years ago
Published Linked with GitHub

Модели рубрик


Над и подрубрики


Базовой модели, в которой будут храниться и надрубрики, и подрубрики, мы дадим имя 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>
Select a repo