Курс по Django: https://stepik.org/a/183363
Архив проекта: 41_sitewomen.zip
Продолжаем
знакомиться с настройкой админ-панели Django и на этом
занятии увидим, как можно управлять внешним видом и функционалом страницы
добавления и редактирования отдельных постов.
https://docs.djangoproject.com/en/4.2/ref/contrib/admin/
Если перейти на
редактирование какой-либо записи, то фреймворк Django автоматически
сформирует страницу с набором всех редактируемых полей, которые мы с вами
определяли для модели Women. Мы здесь не видим только поля time_create
и time_update, значения которых формируются автоматически.
Набор и свойства
отображаемых полей можно настраивать. Например, в классе WomenAdmin можно
определить атрибут fields со списком отображаемых на форме полей:
@admin.register(Women)
class WomenAdmin(admin.ModelAdmin):
fields = ['title', 'content', 'slug']
...
Обновляем
страницу и видим только эти три поля. Причем поля отображаются в порядке их
перечисления в атрибуте fields. Если порядок поменять,
например:
fields = ['title', 'slug', 'content']
то поля в форме
также поменяют свое положение.
Давайте теперь попробуем
добавить новую запись по женщинам в форму только с тремя полями. Например:
title: Екатерина Гусева
slug: ekaterina-guseva
content: Биография Екатерины Гусевой
Нажимаем кнопку
«Сохранить», и видим ошибку. Она возникла из-за того, что у нас заполнены не
все обязательные поля. В частности, поле «Категория». Но мы и не могли его
заполнить, так как его нет в форме. Поэтому здесь, конечно, нужно отображать
все обязательные поля. Давайте добавим еще категории:
fields = ['title', 'slug', 'content', 'cat']
Теперь при
заполнении и сохранении новой записи у нас не возникает никаких проблем.
Или можно
сделать наоборот. Указать список исключаемых полей. Это делается с помощью
атрибута exclude, например,
следующим образом:
@admin.register(Women)
class WomenAdmin(admin.ModelAdmin):
# fields = ['title', 'slug', 'content', 'cat']
exclude = ['tags', 'is_published']
...
На форме увидим
все поля, кроме тэгов и статуса.
Далее, мы можем
сделать поля только для чтения. Для этого используется коллекция readonly_fields:
@admin.register(Women)
class WomenAdmin(admin.ModelAdmin):
# fields = ['title', 'slug', 'content', 'cat']
readonly_fields = ['slug']
exclude = ['tags', 'is_published']
Причем это поле
будет отображено в самом низу. Чтобы сохранить нужный порядок, оставим
коллекцию fields и уберем
коллекцию exclude:
@admin.register(Women)
class WomenAdmin(admin.ModelAdmin):
fields = ['title', 'slug', 'content', 'cat', 'husband']
readonly_fields = ['slug']
...
Теперь поля
следуют в порядке списка fields. Но при добавлении новой записи
у нас поле slug первый раз будет
пустым, а второй раз запись добавиться не сможет, т.к. нарушается уникальность
слага. Поправить это можно двумя способами. Забегая вперед, отмечу, что в момент
сохранения записи вызывается метод save() у модели. Это
значит, мы можем в модели Women переопределить этот метод и сделать
автозаполнение слага:
class Women(models.Model):
...
def save(self, *args, **kwargs):
self.slug = slugify(self.title , allow_unicode=True)
super().save(*args, **kwargs)
...
Правда, в этом
случае slug заполняется
русскими символами, что не очень хорошо. При попытке открыть такой пост у нас
возникнет ошибка конвертора slug в маршруте.
Исправить это
можно с помощью самой известной техники программирования – костыля. Перед
классом Women объявим метод,
который будет переводить русские символы в латиницу следующим образом:
def translit_to_eng(s: str) -> str:
d = {'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd',
'е': 'e', 'ё': 'yo', 'ж': 'zh', 'з': 'z', 'и': 'i', 'к': 'k',
'л': 'l', 'м': 'm', 'н': 'n', 'о': 'o', 'п': 'p', 'р': 'r',
'с': 's', 'т': 't', 'у': 'u', 'ф': 'f', 'х': 'h', 'ц': 'c', 'ч': 'ch',
'ш': 'sh', 'щ': 'shch', 'ь': '', 'ы': 'y', 'ъ': '', 'э': 'r', 'ю': 'yu', 'я': 'ya'}
return "".join(map(lambda x: d[x] if d.get(x, False) else x, s.lower()))
Параметр allow_unicode=True уберем, так как
он теперь не нужен, и снова сохраним пост. Увидим слаг, записанный латинскими
символами. Теперь мы можем посмотреть статью на сайте без каких-либо ошибок.
Но есть путь
гораздо проще, но он применим только для админ-панели. Уберем метод save() из модели Women, а в классе WomenAdmin
пропишем следующий атрибут:
class WomenAdmin(admin.ModelAdmin):
fields = ['title', 'slug', 'content', 'cat', 'husband']
# readonly_fields = ['slug']
prepopulated_fields = {"slug": ("title",)}
...
Теперь при
изменении поля title, поле slug будет
автоматически заполняться корректными латинскими символами, формируя слаг.
Если у вас этот
атрибут не сработал, то очистите поля title и slug, нажмите кнопку
«Сохранить» и, возможно, это поможет.
В заключение
этого занятия давайте посмотрим, как можно работать и настраивать виджет для
типа связи многие ко многим. В модели Women за нее отвечает
атрибут tags. Выведем ее в
форму (в классе WomenAdmin):
fields = ['title', 'slug', 'content', 'cat', 'husband', 'tags']
Откроем запись с
проставленными тегами и видим, что они подсвечиваются серым цветом. Мы можем
менять их, нажав на кнопку Ctrl и кликая мышкой по этому списку.
Но этот же
виджет можно отобразить в форме и по-другому. Если перейти в класс WomenAdmin и прописать
атрибут:
filter_horizontal = ['tags']
то увидим
расширенное представление для работы со списком тегов. Часто это бывает гораздо
удобнее.
Или, по
аналогии, можно прописать вертикальный фильтр:
filter_vertical = ['tags']
и в этом случае
окошки располагаются по вертикали со всем прежним функционалом.
Вот такие
настройки существуют для формирования желаемого вида формы редактирования
отдельных записей.
Курс по Django: https://stepik.org/a/183363