Классическая доска объявлений подразумевает, что все объявления разделены на тематические рубрики (электроника, услуги, аренда и т.д). Также добавим данный функционал в наш проект.
Сначала объявим новый класс модели Rubric, которая обеспечит функционирование рубрик. Для этого необходимо дописать код в models.py (приложение bboard):
Class Rubric(models.Model): name = models.CharField(max_length=30, db_index=True, verbose_name='Название') class Meta: verbose name_plural = 'Рубрики' verbose_name = 'Рубрика' ordering = ['name']
Создаваемая модель содержит только одно поле name, предназначенное для хранения названия рубрики. Сразу инициируем создание индекса, поскольку будет организована сортировка по названию.
Далее необходимо в модель Bb добавить внешний ключ, который обеспечит связь между записью модели Rubric и текущей записью (объявление-рубрика). Данная связь будет иметь тип «один-со-многими» – запись модели Rubric будет связана с некоторым количеством записи модели Bb. При этом модель Rubric будет первичной.
Теперь добавим в модель Bb новое поле – rubric:
Class Bb(models.Model): . . . Rubric = models.ForeignKey('Rubric', null=True, on_delete=models.PROTECT, verbose_name='Рубрика') class Meta: . . .
Класс ForeignKey – поле внешнего ключа, который используется для хранения ключа записи из первичной модели. При помощи первого параметра в конструктор класса передается имя класса первичной модели, поскольку первичная модель у нас объявлена после вторичной.
По умолчанию все поля моделей обязательны к заполнению. Поэтому нет возможности добавить новое поле, также обязательное к заполнению – возникнет ошибка на уровне СУБД. Придется явно сделать поле rubric необязательным к заполнению при помощи параметра null (значение True).
Действия при каскадном удалении записей вторичной модели настраиваются при помощи именованного параметра on_delete. Значение PROTECT запрещает каскадное удаление. Это сделано, чтобы даже при удалении рубрики объявления оставались.
Применение миграций
После сохранения изменений необходимо сгенерировать миграции, чтобы все изменения в структуре базы данных были зафиксированы:
manage.py makemigrations bboard
После данной команды в каталоге migrations будет автоматически создан новый файл миграции с названием в формате 0002_auto_<дата_время>. Можно открыть файл и посмотреть его содержимое – там будут инструкции для создания новой таблицы для модели Rubric, а также для добавления нового поля rubric в таблицу модели Bb.
Применим созданный файл миграции:
manage.py migrate
Сразу зарегистрируем созданную модель на административном сайте, для чего добавим в модель admin.py две строки:
from .models import Rubric admin.site.register(Rubric)
Активируем отладочный веб-сервер, перейдет в административную панель и вручную добавим в модель Rubric несколько рубрик (например, «Транспорт» и «Недвижимость»).
Строковое представление модели
Изменения успешно применены, однако в списке записей все рубрики отображаются в виде малоинформативного шаблона <имя класса модели>object(<ключ>).
Один из способов решения – объявить для модели Rubric специальный класс редактора, в котором указать набор полей для вывода (ранее уже рассматривалось). Но данный способ лучше подходит для моделей, которые имеют несколько значащих полей (в данном случае поле только одно).
Рассмотрим другой способ – переопределение метода __str__(self), возвращающего строковое представления класса. Добавим в модуль models.py следующий код:
Class Rubric(models.Model): . . . def __str__(self): return self.name class Meta: . . .
Теперь в качестве строкового представления будет выводиться название рубрики.
Откроем список записей модели Bb и отредактируем созданные ранее объявления, указав соответствующую рубрику (доступны в раскрывающемся списке).
Осталось сделать так, чтобы в рубрики выводились также в списке записей модели Bb. Для этого достаточно в класс Bbadmin добавить поле ‘rubric’ в перечень имен полей, присвоенный атрибуту list_display:
class Bbadmin(admin.ModelAdmin): List_display = ('title', 'content', 'price', 'published', 'rubric') . . .