Сохранение URL как условие изменения
Для обновления старого сайта важно различать имя исходного файла и публичный адрес. В нашей библиотеке документ urls.md связан с адресом, который заканчивается на .php. Python-программа читает Markdown, но это не означает, что посетитель обязан получить новый адрес .html. В этом уроке зафиксируем соответствие идентификатора и URL как отдельное условие изменения. Оно станет основой ревью будущего отбора рекомендуемых страниц.
Речь идёт о модели данных учебного проекта. Мы не переносим настоящий хостинг, не настраиваем сервер и не утверждаем, что реальное ранжирование ProfessorWeb проверено. Задача уже: не менять значения адресов при локальном изменении функции. Сохранение URL является важной частью миграции, но дополнительно потребуются корректная выдача, ссылки, canonical и другие свойства, которые не доказываются одним JSON-файлом.
Адрес является данными
В manifest.json у записи есть поле url. Оно читается напрямую и передаётся в краткий объект вывода. Программа не выводит его из id, не заменяет расширение и не добавляет новый раздел по названию курса. Благодаря этому локальное перемещение Markdown не обязано менять ссылку для посетителя. Идентификатор отвечает за поиск записи внутри программы, имя файла — за чтение текста, URL — за публичную точку входа.
Популярное сокращение '/articles/' + id + '.html' выглядит удобным, пока у всех страниц единая история. В старом каталоге адреса часто неоднородны: встречаются вложенные директории, исторические ошибки в названиях и прежние расширения. Автоматическая нормализация может создать сотни новых адресов без явного решения владельца. Даже если контент сохранён, внешние ссылки продолжат обращаться к прежним путям. Поэтому наше условие запрещает вычислять новый URL в функции отбора.
Файл url-baseline.json содержит словарь: ключом является устойчивый идентификатор, значением — исходный адрес. Он нужен для сравнения, а не для второго независимого редактирования. Основным источником остаётся манифест. Если одновременно вручную менять оба файла ради прохождения проверки, основание исчезнет: новый реестр уже не описывает исходное состояние. Снимок следует создавать до изменения и хранить как договорённость о том, что требуется сохранить.
Какая операция меняет ссылку
Рассмотрим добавление рекомендуемой карточки. Карточка получает запись, читает название и адрес и показывает ссылку. Новое поле выбора может влиять на присутствие записи на главной, но не на сам адрес. Следовательно, отсутствие ссылки среди рекомендованных не означает удаления страницы. Это важное различие для старых уроков: компактная главная может скрыть длинные оглавления, если каталог и учебные маршруты продолжают давать обычные переходы к материалам.
Наш пример пока не формирует HTML и не обходится поисковым роботом. Он только показывает, на каком уровне можно сохранить ссылку. Когда такой отбор включается в настоящий шаблон, следует проверить, что href получает прежнее значение, а страница продолжает выдаваться по этому пути. Нельзя заменить эту связь обещанием «SEO не пострадает». Каждое дополнительное свойство требует своего наблюдения; сохранённый объект Python ещё не является успешным HTTP-ответом.
Отдельно подумайте о параметрах запроса. В нашей библиотеке url содержит только заданный путь страницы, и программа не изменяет его. У реального сайта могут существовать адреса поиска, пагинации и фильтров с query. Их нельзя автоматически приравнять к самостоятельным статьям или удалить ради красивого списка. Сначала устанавливают назначение адреса и его фактическую историю, затем выбирают сохранение, перенаправление или канонический вариант. Эта серия не внедряет универсальное правило для всех query.
Ревью условия сохранения
Для нашей задачи достаточно сопоставить три предмета: исходный реестр, текущий манифест и код формирования результата. Если значения манифеста не менялись, но программа переписывает расширение при выводе, условие всё равно нарушено. Если программа отдаёт прежний URL, но исполнитель удалил запись из манифеста, адрес может пропасть из маршрута данных. Поэтому проверка относится не только к diff одного JSON, а к пути выбранной записи до результата.
Дублирование URL загрузчик отклоняет. Две разные записи с одинаковым адресом создают неоднозначность: какая статья является содержимым этой страницы? В небольшой библиотеке безопаснее остановиться с понятной причиной, чем выбирать последнюю запись молча. Это не решение проблемы всех исторических дублей настоящего сайта. Если прежний сайт намеренно имеет несколько входов к одному материалу, их нужно описать отдельным контрактом алиасов и выдачи, которого в этом примере нет.
Переименование urls.md в permalinks.md при одновременной корректировке поля file может быть допустимым в другой задаче, поскольку URL остаётся тем же. Но в текущем контракте корпус и манифест доступны только для чтения. Не путайте техническую возможность сохранения адреса с разрешением выполнить любое сопутствующее перемещение. Хороший агент сначала завершает указанную область изменения, а предложение о реорганизации оформляет отдельно с объяснением её цели.
Ожидаемый результат чтения состояния lesson-04 — полный реестр четырёх исходных адресов и программа, которая передаёт их напрямую. Реального запуска или сетевой проверки здесь не было. При самостоятельном исследовании можно сравнить результат публичного вывода с реестром: три видимые записи должны иметь одинаковые URL в обоих источниках. Частная заметка остаётся в исходном договоре, но не становится публичной из-за наличия адреса.
Переименование без нового адреса
Рассмотрим мысленный вариант: файл urls.md получает новое имя, но id и url сохраняются. Для читателя адрес остаётся прежним, а загрузчик должен открыть новый file из манифеста. Такой вариант демонстрирует независимость трёх имён. Однако наша текущая задача запрещает править корпус и манифест, поэтому он не выполнен в архиве. Мы используем его для понимания модели, а не сообщаем о состоявшейся миграции.
Если позже оператор поручит переименование, в отчёте нужно разделить два результата: файл перемещён и публичный адрес не менялся. Для второго недостаточно только нового имени Markdown; следует проследить потребителя поля url. Если настоящий сборщик вычисляет путь страницы из имени файла вопреки манифесту, сохранённое значение в JSON не исправит выдачу. Договор данных должен быть реализован тем компонентом, который создаёт конечный путь.
Поэтому отдельный реестр полезен как предмет сравнения, но не является магической защитой трафика. Он указывает, что требуется сохранить, и помогает найти расхождение. Проверка ответа рабочего сайта, canonical и ссылок остаётся самостоятельным этапом, когда реальная интеграция будет подготовлена и разрешена.
Следующий урок добавит новый отбор поверх этой модели. Если исполнитель предложит одновременно сменить структуру адресов, такую часть кандидата можно сразу отделить: она не нужна для рекомендуемых материалов. Зафиксированное условие делает разговор о миграции точнее и даёт основу для небольшого проверяемого изменения без перестройки всех страниц библиотеки.
Полный файл url-baseline.json из состояния lesson-04. Полное самостоятельное состояние находится в архиве серии; фрагмент не заменяет остальные определения.
{
"urls": "/my/csharp/charp_theory/level1/1_1.php",
"markdown": "/articles/markdown-example.html",
"sitemap": "/articles/sitemap-example.html",
"notes": "/articles/private-note.html"
}
Статус примера: not_run. При подготовке не выполнялись учебные программы, тесты, вызовы AI или деплой. Описанные эффекты ожидаемые.
Оглавление серии · Полные исходники
Первичные документы: Источник 1.