Как сделать меню в django

Добавил пользователь Cypher
Обновлено: 10.09.2024

Фреймворк Django поставляется с мощным инструментом администрирования под названием admin. Вы можете использовать его прямо из коробки, чтобы быстро добавлять, удалять или редактировать любую модель базы данных из веб-интерфейса. А можете, написав немного кода, самостоятельно настроить Django admin и вывести свои административные возможности на новый уровень.

В этом руководстве вы узнаете, как:

  • Добавить столбцы атрибутов в список объектов модели.
  • Добавить ссылки на страницы других объектов.
  • Добавить фильтры в список объектов модели.
  • Добавить поиск в список объектов модели.
  • Изменить форму редактирования объекта.
  • Переопределить шаблоны Django admin.

Предварительные условия

Чтобы получить максимум от этого руководства, вы должны быть знакомы с Django, особенно с моделями. Поскольку Django не является частью стандартной библиотеки Python, то вы также должны быть знакомы с pip и pyenv (или аналогичным инструментом виртуального окружения). Чтобы узнать больше об этих темах, можете ознакомиться со следующими ресурсами:

Фрагменты кода в этом руководстве были протестированы на Django 3.0.7. Они должны работать в любой версии, которую вы используете, но могут быть незначительные различия.

Настройка Django Admin

Django admin предоставляет веб-интерфейс для создания и управления объектами модели базы данных. Чтобы увидеть его в действии, вам сначала понадобится проект Django и несколько моделей. Установите Django в чистое виртуальное окружение:

Сначала создайте новый проект Django под названием School с приложением под названием core . Затем выполните команду migrate и создайте администратора. Доступ к админ-панели Django разрешен только пользователям с флагами staff или superuser , поэтому для создания суперпользователя используется команда createsuperuser .

Вам также необходимо внести изменения в файл School/settings.py, чтобы включить новое приложение с именем core :

Каталог приложения core будет содержать следующие файлы:

Из этих файлов нас интересуют два:

  1. models.py, в котором определяются модели.
  2. admin.py, в котором модели регистрируются в Django admin.

Чтобы продемонстрировать кастомизацию Django admin, вам понадобятся несколько моделей. Отредактируйте core/models.py следующим образом:

Эти модели представляют учащихся, проходящих курсы в школе. У модели Course есть два поля: название курса и год, в котором он был начат. Модель Person имеет три поля: имя и фамилия учащегося и курсы, которые он проходит (ноль или более). Grade содержит оценку, полученную учащимся ( Person ) на курсе ( Course ).

Вот диаграмма, показывающая отношения между объектами:


Имена таблиц в базе данных немного отличаются от этих, но они связаны с моделями, показанными выше.

Каждую модель, которую вы хотите отображать в админ-панели Django, необходимо зарегистрировать. Делается это в файле admin.py. Модели из core/models.py регистрируются в соответствующем файле core/admin.py:

Вы почти готовы к работе. После выполнения миграции вы можете запустить сервер разработки Django и увидеть следующие результаты:

django admin

Теперь вы можете использовать админ-панель для создания объектов в своей базе данных. Щелкнув по названию модели, вы увидите список всех объектов в базе данных для этой модели. Вот, например, список людей ( Person ):

django admin

Сначала список пустой, как и ваша база данных. Нажав ADD PERSON, вы можете создать человека в базе данных. После сохранения вы вернетесь к списку объектов Person :

django admin

Хорошая новость в том, что у вас есть объект. Плохая новость в том, что Person object (1) сообщает вам id объекта и ничего больше. По умолчанию, Django admin отображает каждый объект, вызывая функцию str() . Вы можете сделать эту страницу более полезной, добавив метод .__str__() в класс Person в core/models.py:

Добавление метода Person.__str__() изменяет отображение: теперь вместо id отображаются имя и фамилия человека. Вы можете обновить страницу, чтобы увидеть изменения:

django admin

Так-то лучше! Теперь вы можете увидеть некоторую информацию об объекте Person . Рекомендуется добавить подобные методы как к объектам Course , так и к объектам Grade :

Чтобы увидеть полный эффект от вашей кастомизации, вам нужно иметь некоторые данные в своей базе данных. Вы можете создать свои собственные данные прямо сейчас, или можете пропустить этот шаг и использовать фикстуры (fixture).

Django позволяет загружать данные в базу данных и выгружать из нее с помощью файлов, называемых фикстурами. Скопируйте следующее в файл с именем core/fixtures/school.json:

Создав файл, вы можете использовать команду loaddata , чтобы загрузить его в свою базу данных:

Теперь в вашей базе данных есть несколько объектов Person , Course и Grade .

А сейчас, когда у вас есть некоторые данные для работы, вы готовы приступить к кастомизации админ-панели Django.

Кастомизация Django Admin

Умные люди, создавшие фреймворк Django, не только создали админку, но и сделали это таким образом, чтобы вы могли кастомизировать ее для своих проектов. Когда вы ранее регистрировали объект PersonAdmin , он наследовался от admin.ModelAdmin . Большая часть настроек, которые вы можете сделать с помощью Django admin, выполняется путем модификации класса ModelAdmin , и вы, конечно, можете изменять его!

ModelAdmin имеет более тридцати атрибутов и почти пятьдесят методов. Вы можете использовать каждый из них для настройки админ-панели и управления интерфейсами ваших объектов. Каждый из этих вариантов подробно описан в документации.

В довершение ко всему, админка построена с использованием шаблонов Django. Механизм шаблонов Django позволяет вам переопределять существующие шаблоны, а поскольку Django admin — это просто еще один набор шаблонов, это означает, что вы можете полностью изменить его HTML-код.

Хотя это выходит за рамки данного руководства, вы даже можете создать несколько сайтов администрирования. Это может показаться излишним, но это позволяет вам фантазировать и делать разные сайты для пользователей с разными разрешениями.

Django admin разделен на три основные области:

  1. App index
  2. Change lists
  3. Change forms

В предыдущем примере app index отображал объекты Person , Course и Grade . При нажатии на People отображаются change list’ы для объектов Person . На странице change list, щелкнув по объекту Buffy Summers, вы попадете на страницу change form, чтобы отредактировать данные о Buffy Summers.

Изменение Change List с помощью list_display

Реализация метода .__str__() — это быстрый способ изменить представление объекта Person с бессмысленной строки на понятные данные. Поскольку это представление также будет отображаться в раскрывающихся списках со множественным выбором, вы определенно захотите сделать его максимально простым и понятным.

Вы можете кастомизировать страницу change list гораздо большим количеством способов, чем просто изменить строковое представление объекта. Атрибут list_display объекта admin.ModelAdmin указывает, какие столбцы будут отображаться в change list’e. Это значение представляет собой кортеж атрибутов моделируемого объекта. Например, в core/admin.py измените PersonAdmin следующим образом:

Приведенный выше код модифицирует ваш Person change list таким образом, что теперь будут отображаться атрибуты last_name и first_name для каждого объекта Person . Каждый атрибут отображается в столбце на странице:


Эти два столбца кликабельны, что позволяет сортировать страницу по данным столбца. Django admin также учитывает атрибут ordering в Meta-классе:

Добавление атрибута ordering приведет к тому, что по умолчанию все запросы к Person будут упорядочены по last_name , а затем по first_name . Django будет соблюдать этот порядок по умолчанию как в админке, так и при получении объектов.

Кортеж list_display может ссылаться на любой атрибут объекта. Он также может ссылаться на метод в самом admin.ModelAdmin . Снова изменим PersonAdmin :

В приведенном выше коде вы добавляете столбец, в котором будет отображаться средний бал каждого учащегося. show_average() вызывается один раз для каждого объекта, отображаемого в списке.

Параметр obj — это объект для отображаемой строки. В этом случае вы используете его для запроса соответствующих объектов Grade для учащегося, затем получаете среднее значение Grade.grade . Вы можете увидеть результаты здесь:


Имейте в виду, что средний бал на самом деле нужно рассчитывать в объекте модели Person . Скорее всего, вам понадобятся данные, находящиеся где-нибудь еще, а не только в Django admin. Если бы у вас был такой метод, вы могли бы добавить его в атрибут list_display . Приведенный пример показывает, что вы можете делать в объекте ModelAdmin , но, вероятно, это не лучший выбор для вашего кода.

По умолчанию сортируются только те столбцы, которые являются атрибутами объекта. show_average() — нет. Это связано с тем, что сортировка выполняется с помощью QuerySet. В некоторых случаях есть способы сортировки этих столбцов, но это выходит за рамки нашего руководства.

Заголовок столбца основан на имени метода. Вы можете изменить заголовок, добавив атрибут к методу:

По умолчанию Django защищает вас от HTML в строках, если строка является результатом пользовательского ввода. Чтобы отображение включало HTML, вы должны использовать format_html() :


К сожалению, в Django еще не добавлена поддержка f-строк для format_html() , поэтому используется синтаксис str.format() .

Добавление ссылок на страницы других объектов

Объекты довольно часто ссылаются на другие объекты с помощью внешних ключей (foreign key). Вы можете указать в list_display метод, возвращающий ссылку HTML. Внутри core/admin.py измените класс CourseAdmin следующим образом:

Теперь Course change list состоит из трех столбцов:

  1. название курса.
  2. год, в котором был начат курс.
  3. ссылка, отображающая количество учащихся, проходящих курс.

Вы можете увидеть результат на следующем скриншоте:


Когда вы нажимаете по ссылке 2 Students, вы попадаете на страницу Person change list с примененным фильтром. На отфильтрованной странице показаны только ученики из Psych 101: Buffy и Willow. Xander не поступил в университет.

В примере кода для поиска URL-адреса в админке используется функция reverse() . Вы можете найти любую страницу Django admin, используя следующее соглашение об именах:

Эта структура имени разбивается следующим образом:

  • admin: — это пространство имен.
  • app — это название приложения.
  • model — это объект модели.
  • page — это тип страницы Django admin.

В приведенном выше примере view_students_link() вы используете admin:core_person_changelist , чтобы получить ссылку на страницу change list объекта Person в приложении core .

Я пытаюсь иметь два отдельных меню в своем django-cms приложении. Один для заголовка и другого с различным набором связей для нижней сноски:

, Как я могу создать два отдельных меню?

Зависит, что вы хотите сделать действительно, но у меня есть основной шаблон, у которого есть навигационное меню наверху и подменю карты сайта в основании.

Так начинаясь с навигации;

Который использует шаблон;

Тогда карта сайта;

Понимание вариантов (числа), можно предусмотреть меню, может позволить вам показать различные части своего сайта, но если построенные в признаках меню не удовлетворяют вашим потребностям, вы могли бы написать признак пользовательского меню.

Последним, что нам стоит сделать для нашего веб-сайта, является удобный способ добавления и редактирования записей. admin -панель Django удобна, но её дизайн сложно изменять. С forms (формами) у нас будет абсолютная власть над интерфейсом блога — мы сможем сделать практически всё, что только можно придумать!

Формы Django удобны тем, что мы можем создать новую форму с нуля или воспользоваться ModelForm для сохранения содержимого формы в модель.

Это как раз то, что нам нужно сделать: мы создадим форму для модели Post .

Как и любая важная часть Django, формы имеют свой собственный файл: forms.py .

Нам нужно создать файл с таким именем в директории blog .

Теперь открой его и набери следующее:

Для начала нам нужно импортировать формы Django ( from django import forms ) и, разумеется, нашу модель Post ( from .models import Post ).

PostForm , как ты, вероятно, подозреваешь, — это имя для нашей формы. Нам нужно также сообщить Django, что эта форма относится к ModelForm (чтобы он смог поколдовать для нас) — forms.ModelForm поможет с этим.

Дальше у нас class Meta , где мы определяем, какая модель будет использоваться для создания формы ( model = Post ).

В завершение мы можем указать, какие поля должны присутствовать в нашей форме. Сейчас нам требуются только поля title и text — author будет автоматически выбран в зависимости от авторизованного пользователя (тебя), а created_date должна автоматически проставляться в момент создания записи (т.е. через код), верно?

Вот и всё! Теперь мы можем использовать форму в представлении и отобразить её в шаблоне.

Поэтому снова нам необходимо создать ссылку на страницу, URL-адрес, представление и шаблон.

Ссылка на страницу с формой

Пришло время открыть файл blog/templates/blog/base.html . Мы добавим ссылку в элемент div с именем page-header :

Обрати внимание, что мы назвали новое представление post_new . Класс glyphicon glyphicon-plus определён в используемой нами теме bootstrap — таким образом мы выведем значок плюса.

После добавления строки твой html-файл должен выглядеть следующим образом:

Нам нужно открыть файл blog/urls.py и добавить строку:

Окончательная версия файла будет выглядеть следующим образом:

После перезагрузки веб-сайта мы увидим ошибку AttributeError , поскольку представление post_new не реализовано. Давай добавим его прямо сейчас.

Представление post_new

Самое время открыть файл blog/views.py и добавить следующую строку к остальным, начинающимся с from :

А затем наше представление:

Чтобы создать новую форму Post , нам потребуется вызвать PostForm() и передать её шаблону. Мы ещё вернёмся к этому представлению, а пока давай быстро создадим шаблон под форму.

Шаблон

Нам нужно создать файл post_edit.html в директории blog/templates/blog . Чтобы заставить форму работать, нам потребуется несколько вещей:

  • Нам нужно отобразить форму. Мы можем сделать это, к примеру, простым > .
  • Строка выше должна быть обёрнута в HTML-теги
  • Нам потребуется кнопка Save . Мы добавим её при помощи HTML-кнопки: Save
  • И, наконец, сразу после открытия тега мы должны добавить . Это очень важно, поскольку так мы делаем форму защищённой! Django будет ругаться, если ты забудешь добавить этот код:

Хорошо, давай посмотрим, как должен выглядеть HTML-код в файле post_edit.html :

Время обновить страницу! Ура! Форма отображается!

Новая форма

Но подожди минутку! Если ты наберёшь что-нибудь в полях title и text и попробуешь сохранить — что произойдёт?

Ничего! Мы снова на той же странице и наш текст пропал. и новая запись не была добавлена. Так что же пошло не так?

Ответ прост: ничего. Нам нужно сделать кое-что ещё, чтобы новое представление заработало.

Сохраняем данные из формы

Снова открой файл blog/views.py . Всё, что у нас есть в представлении post_new , выглядит пока следующим образом:

После отправки формы мы возвращаемся к тому же представлению, но в этот раз с новыми данными в request , а точнее, в request.POST (имя POST не имеет ничего общего с "постом" в блоге, оно связано с тем, что мы "публикуем" данные). Помнишь, что в HTML-файле определение имеет параметр method="POST" ? Все поля формы теперь находятся в request.POST . Ты не должна переименовывать POST во что-то другое (другое доступное значение параметра method — GET , но у нас сейчас нет времени объяснять разницу).

Получается, что в представлении view нам нужно обработать две разные ситуации. Первая: когда мы только зашли на страницу и хотим получить пустую форму. Вторая: когда мы возвращаемся к представлению со всей информацией, которую мы ввели в форму. Таким образом, нам потребуется ввести условие (для этого мы будем использовать условный оператор if ):

Теперь заполним строку, занятую [. ] . Если method — POST , тогда мы хотим построить PostForm с данными из формы, верно? Мы добьёмся этого следующим образом:

Легко! Дальше мы проверим, корректна ли форма (все ли необходимые поля заполнены и не отправлено ли некорректных значений). Мы сделаем это при помощи form.is_valid() .

Мы проверяем, допустимо ли содержимое формы, и, если всё в порядке, сохраняем её!

Фактически мы выполняем две операции: сохраняем форму form.save и добавляем автора (поскольку обязательного поля author нет в PostForm !). commit=False означает, что мы пока не хотим сохранять модель Post — сначала нужно добавить автора. В основном ты будешь использовать form.save() , без commit=False , но в данном случае нам это пригодится. post.save() сохранит изменения (после добавления автора), и новая запись будет создана!

Наконец, будет прекрасно, если мы сможем сразу переходить к странице post_detail после добавления новой записи, согласна? Для этого нам понадобится еще один импорт:

Добавь эту строку в начало файла. Теперь мы можем сделать переадресацию на страницу post_detail для созданной записи:

post_detail — это имя представления, которое нам необходимо. Помнишь, что это представление требует переменную pk ? Чтобы передать её представлению, мы используем аргумент pk=post.pk , где post — это новая запись в блоге!

Хорошо, мы многое обсудили, пора взглянуть на представление полностью, верно?

Возможно, ты заметила, что мы устанавливаем дату публикации перед сохранением поста. В последствии мы сделаем кнопку публикации в Django Girls Tutorial: Extensions.

Ошибка при выходе из аккаунта

Валидация формы

Теперь мы покажем тебе, насколько круты формы в Django. Запись в блоге должна иметь поля title и text . В нашей модели Post мы не указываем, что эти поля необязательны (в отличие от published_date ), так что Django по умолчанию будет ожидать, что пользователь их заполнит.

Попробуй сохранить форму с незаполненными полями title и text . Угадай, что произойдёт!

Валидация формы

Django заботится о проверке всех полей в нашей форме на корректность. Разве не шикарно?

Форма редактирования

Теперь мы знаем, как добавить новую форму. Но что, если мы хотим внести исправления в уже существующую запись? По сути это схожая с предыдущей задача. Давай быстро создадим пару важных вещей (если ты чего-то не понимаешь, спроси своего тренера или загляни в предыдущие главы, поскольку мы уже объясняли все необходимые шаги).

Открой blog/templates/blog/post_detail.html и добавь следующую строку:

так, чтобы шаблон выглядел следующим образом:

В файле blog/urls.py добавь:

Мы будем использовать повторно шаблон blog/templates/blog/post_edit.html , так что осталось лишь отсутствующее представление.

Давай откроем файл blog/views.py и добавим в самый конец следующее:

Выглядит практически идентично представлению post_new , верно? Но не совсем. Во-первых, мы передаём параметр pk из URL-адреса. Кроме того, мы получаем модель Post для редактирования при помощи get_object_or_404(Post, pk=pk) и передаём экземпляр post в качестве instance форме и при сохранении…

… и когда мы открываем форму для редактирования:

Хорошо, давай удостоверимся, что всё работает! Перейди на страницу post_detail . Ты должна увидеть кнопку редактирования в правом верхнем углу:

Когда ты её нажмёшь, то увидишь форму с выбранной записью:

Форма редактирования

Поменяй заголовок и текст, а затем сохрани запись!

Поздравляем! Твое приложение становится всё более сложным!

Безопасность

Круто иметь возможность создавать новые посты, просто перейдя по ссылке! Однако сейчас кто угодно из посетителей твоего сайта может создать новую запись в блоге, а это, скорее всего, совсем не то, чего бы тебе хотелось. Давай сделаем так, чтобы кнопка показывалась для нас, а не кого-либо ещё.

В файле blog/templates/blog/base.html найди page-header div и тег , который мы добавили ранее. Должно выглядеть примерно так:

Мы добавим сюда ещё один тег , чтобы ссылка показывалась только пользователям, вошедшим в админку. То есть пока что — только тебе! Измени тег , чтобы получилось так:

Из-за этого ссылка будет отправлена в браузер, только если запрашивающий страницу пользователь вошёл в систему. Это не обезопасит создание новых постов полностью, но для начала и это неплохо. Мы подробнее рассмотрим вопросы безопасности в дополнении к учебнику.

Помнишь иконку редактирования, которую мы добавили на страницу поста? Чтобы посторонние не смогли менять уже созданные посты, нам нужно изменить страничку похожим образом.

Открой файл blog/templates/blog/post_detail.html и найди такую строку:

Замени её на следующее:

Поскольку ты авторизована, никаких изменений после обновления страницы ты не увидишь. Но попробуй загрузить страницу в другом браузере или в режиме инкогнито, и увидишь, что ссылка не отобразится!

И последнее: публикация!

Теперь давай посмотрим, как это будет работать на PythonAnywhere. Пришло время для очередного развёртывания!

  • Сначала нам нужно сделать commit и push нового кода в репозиторий GitHub:

(Не забудь подставить вместо свой поддомен на PythonAnywhere без угловых скобок.)

Предположим, что нам нужно добавить отдельную кнопку в списочный интерфейс какой нибудь модели. В данном случае предположим, что это будет кнопка импорта данных. По нажатия на которую будет запускать импорт данных.

Для этого нам нужно будет внести изменения в файл admin.py и добавить дополнительный шаблон админки для соответствующей модели.

Начнем с файла шаблона. Наш шаблон будет основан на стандартном шаблоне, мы просто внесем в него небольшое изменение. В папке соответствующего приложения добавим каталоги: xxx/templates/admin/model_change_list.html.

В этот шаблон добавим следующие изменения.

В файле admin.py добавим указание на файл этот шаблон. Добавим функцию для регистрации нового URL get_urls. В нее добавим маршрут импорта с указанием на функцию импорта. И далее добавим саму функцию, импорта:

Все, для добавление новой кнопки этого достаточно.

Далее будет перевод старой, но все еще актуальной статьи: Haki Benita — How to Add Custom Action Buttons to Django Admin

В последнем посте мы представили шаблон, который мы часто используем в наших моделях Django. Мы использовали приложение по управлению банковского счета с моделями Action и Action, чтобы продемонстрировать, как мы решаем общие проблемы, такие как параллелизм и проверка. У банковского счета было две операции, которые мы хотели выставить в интерфейсе администратора — deposit (добавления на счет) и withdraw (снятие со счета).

Мы собираемся добавить кнопки в интерфейсе администратора Django для ввода и вывода денег со счета, и мы сделаем это менее чем за 100 строк кода!

Как это будет выглядеть в конце?

Почему бы не использовать существующие action в интерфейсе администратора?

Другим недостатком является то, что действия не доступны в detail view. Чтобы добавить кнопки в подробный вид, вам нужно переопределить шаблон.

Формы

Прежде всего, нам нужно получить дополнительные данные от пользователя для выполнения действия. Естественно для этого, нам нужна форма. Нам нужна одна форма для deposit и одна форма для withdraw.

Все наши actions имеют общие аргументы, такие как comment и send_email. Actions также обрабатывают успех и неудачу аналогичным образом.

Давайте начнем с базовой формы для обработки общего action:

Теперь, когда у нас есть простой базовый класс, давайте добавим форму для withdraw. Для withdraw нам нужно добавить поле суммы:

  • Мы расширили базу AccountActionForm и добавили поле amount с соответствующими проверками.
  • Мы заполнили необходимые атрибуты, email_body_template.
  • Мы реализовали action формы, используя classmethod из предыдущего поста. Модель заботится о блокировке записи, обновлении любых вычисляемых полей и добавлении соответствующих действий в журнал.

Следующим шагом является добавление deposit. Для deposit требуются поля amount, reference и reference_type:

На данный момент мы получили необходимые формы для принятия, проверки и оформления deposit и withdraw. Следующим шагом является его интеграция в представление списка администратора Django.

Admin

Прежде чем мы сможем добавить кнопки для actions, нам нужно настроить базовую страницу администратора для нашей модели Account:

Примечание: мы можем сделать просмотр списка намного лучше, добавив ссылку на пользователя и actions учетной записи. Мы можем добавить несколько полей поиска и многое другое. Ранее я писал о проблемах производительности в интерфейсе администратора при масштабировании приложения Django для сотен тысяч пользователей. Там есть несколько приятных трюков, которые могут сделать даже этот простой вид намного приятнее.

Добавление кнопок Action

Мы хотим добавить кнопки action для каждой учетной записи и сделать так, чтобы они ссылались на страницу с формой. В Django есть функция для регистрации URL get_urls в виде списка. Давайте использовать эту функцию, чтобы добавить маршруты для наших пользовательских действий:

Давайте перейдем к реализации функций для обработки actions:

Deposit и withdraw осуществляются очень похожим образом. Чтобы выполнить оба действия, мы хотим отобразить форму на промежуточной странице и выполнить действие, когда пользователь отправит форму.

process_action обрабатывает отправку формы для обоих действий. Функция принимает форму, название действия и идентификатор учетной записи. process_withdraw и process_deposit, используются для установки соответствующего контекста для каждой операции.

Для завершения процесса нам нужен template для промежуточной страницы, который содержит форму действия. Мы собираемся основывать наш шаблон на существующем шаблоне, используемом Django Admin:

Теперь наши сотрудники могут легко вносить и снимать средства прямо из интерфейса администратора. Не нужно создавать дорогую панель инструментов.

Я обещал, что мы сделаем это в 100 строк, и мы сделали это за меньше количество!

Заключение

Читайте также: