Приложение для работы с базой данных ГАР в Django

Основные возможности
====================

* Импорт базы ГАР из:
    * архива XML
    * каталога с XML
    * напрямую с сайта http://fias.nalog.ru в формате XML
* Импорт всех существующих справочников и классификаторов ГАР (с возможностью выборочного импорта)
* Возможность хранить данные в отдельной БД

Совместимость
=============

* Гарантируется работа на Django 3.2 и Python 3.9

Описание ключей командной строки (./manage.py gar_load_data)
============================================================


--src <path|filename|url|auto>
    Путь до архива с БД ГАР, каталога, в который предварительно был распакован архив или URL-адрес, с которого требуется скачать импортируемый архив
    Значение `auto` означает автоматическое получение данных с сайта http://fias.nalog.ru

--truncate
    Указывает полностью удалять все данные из таблицы перед импортом в неё

--no-truncate
    Разрешает загрузку данных в непустую БД

--no-transaction
    Производит импорт без транзакции

--update
    Обновляет БД ГАР до актуальной версии (после импорта)

--limit
    Устанавливает размер пачки записей, единовременно загружаемой в БД
    Чем больше размер, тем быстрее импорт (в теории), но дольше обработка ошибок, если таковые возникнут
    По-умолчанию: 10000

--tables
    Задаёт список таблиц для импорта через запятую

--update-version-info, --no-update-version-info
    Указывает, обновлять ли список версий БД ГАР
    По-умолчанию: True

--tempdir TEMPDIR
    Путь к каталогу, где будут размещены временные файлы в процессе импорта
    Каталог должен существовать и быть доступен для записи


Установка
=========

1. Установите `m3-gar`::

        pip install m3-gar

2. Добавьте `m3_gar` в `INSTALLED_APPS`.

5. Если вы желаете использовать отдельную БД под данные ГАР, выполните следующее

* Создайте БД и подключите её в `DATABASES`
* Добавьте параметр::

        GAR_DATABASE_ALIAS = 'gar'

где `gar` - алиас БД в `DATABASES`

* Добавьте в список `DATABASE_ROUTERS`::

        m3_gar.routers.GARRouter

* Выполните::


        python manage.py migrate --database=gar

где `gar` - алиас БД в `DATABASES`

5. Выполните::

        python manage.py migrate


Импорт данных
=============

Расшифровка сокращений
----------------------
* T: Table (Таблица) - импортируемая в данный момент таблица
* L: Loaded (Загружено) - количество уже загруженных в таблицу строк
* U: Updated (Обновлено) - количество обновлённых записей
* FN: Filename (Имя файла) - имя файла импортируемой таблицы

Первоначальная загрузка данных
------------------------------
Существует несколько способов импортировать данные в БД ГАР

Полностью автоматический импорт с сайта ФИАС::

        python manage.py gar_load_data --src auto

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

        # Архив с XML-файлами
        python manage.py gar_load_data --src /path/to/gar_xml.zip
        # Каталог с распакованным содержимым архива
        python manage.py gar_load_data --src /path/to/gar_data/

**Но!**
В случае, если в БД уже есть какие-то данные, скрипт выдаст соответствующее сообщение и прекратит работу.
Такое поведение связано с тем, что при импорте из файла, если версия файла не совпадает с версией данных в какой-то таблице в БД ГАР,
данные в этой таблице могут быть удалены полностью и заменены новыми, при этом
ORM Django при наличии связанных таблиц удалит данные так же и оттуда.
Поэтому, если по этой или какой-то иной причине нужно импортировать всю БД ГАР заново, добавьте флаг *--truncate*::

        python manage.py gar_load_data --src /path/to/gar_xml.zip --truncate

Если скачанный файл не актуален, можно добавить к указанной выше команде флаг *--update* - скрипт сразу после импорта обновит БД до актуальной версии.::

        python manage.py gar_load_data --src /path/to/gar_xml.zip --update

Использование отложенной согласованности БД
--------------------------------------------

Для первоначальной загрузки данных может быть выгодно временно отключить ограничения и индексы БД и выполнять загрузку без транзакции.

Для отключения ограничений предусмотрена команда manage_constraints, генерирующая SQL-код для удаления или восстановления ограничений и индексов полей.

Аргументы:

state
    "enable" или "disable" для включения/отключения ограничений соответственно

Опции:

--fk
    изменение состояния внешних ключей

--unique
    изменение состояния ограничений уникальности

--index
    изменение состояния индексов базы данных

--logged
    изменение состояния журналируемости таблиц БД

--truncate
    очистка данных из базы (см. "Удаление данных из БД" ниже)

--commit
    запись изменений в БД, в противном случае происходит только генерация SQL-кода

Полный порядок действий:

1. Отключить ограничения:::

        python manage.py manage_constraints disable --fk --unique --index --logged --commit

2. Произвести загрузку общих справочников::

        python manage.py gar_load_data --no-truncate --no-transaction /path/to/gar_data/

В директории /path/to/gar_data/ должны лежать файлы AS_*.xml из корня архива, т.е.::

        /path/to/gar_data/AS_ADDHOUSE_TYPES_20211004_91e6dc75-0e20-4af0-8bd4-81701eeb8961.XML
        ...
        /path/to/gar_data/AS_ROOM_TYPES_20211004_5b63b804-601c-4fc2-b083-49a616a30723.XML

3. Произвести частичную загрузку одного или нескольких регионов::

        python manage.py gar_load_data --no-truncate --no-transaction /path/to/gar_data/

В директории /path/to/gar_data/ должны лежать директории с данными по регионам, т.е. для загрузки регионов 01 и 02 должна быть структура вида::

        /path/to/gar_data/01/AS_ADDR_OBJ_20211004_3d78254b-65da-4864-8495-fedad8adcbbf.XML
        ...
        /path/to/gar_data/01/AS_STEADS_PARAMS_20211004_edc5fddf-5a2b-4f47-915b-2300f436fca1.XML
        /path/to/gar_data/02/AS_ADDR_OBJ_20211004_46290f85-8a71-41de-9a8d-b6c01e3f6d60.XML
        ...
        /path/to/gar_data/02/AS_STEADS_PARAMS_20211004_738598d9-38b0-441d-9276-c7ac7e41d606.XML

4. Повторить п.3 для других регионов

5. После успешной загрузки всех данных включить ограничения обратно:::

        python manage.py manage_constraints enable --fk --unique --index --logged --commit


Удаление данных из БД
----------------------
Используется опция --truncate команды manage_constraints.
Принимает ничего, либо список регионов, разделённых запятой.
Для удаления данных по общим справочникам используется регион с кодом "0"
Выполнение происходит с учётом опции "--commit"

Для удаления всех данных::

        python manage.py manage_constraints disable --truncate --commit


Для удаления данных общих справочников::

        python manage.py manage_constraints disable --truncate=0 --commit


Для удаления данных общих справочников и некоторых регионов::

        python manage.py manage_constraints disable --truncate=0,1,2,3 --commit


Для удаления данных некоторых регионов::

        python manage.py manage_constraints disable --truncate=1,2,3 --commit


Обновление существующей БД
--------------------------
Для обновления БД выполните::

        python manage.py gar_load_data --update

Обновление выполняется только с сайта ФИАС. Обновить базу из файла нельзя.


Обновление схемы данных
=======================

Для обновления схемы данных ГАР предоставлена команда `gar_update_schema`

--url
    URL-адрес, с которого требуется скачать архив со схемами в формате XSD

--path
    Путь до уже скачанного архива

--testmode
    Указывает полностью удалять все данные из таблицы перед импортом в неё


Настройка settings.py
=====================
`GAR_DATABASE_ALIAS` - алиас БД в `DATABASES` для данных ГАР



Выкладка дампа в удаленное хранилище
====================================
Для выкладки дампа в удаленное хранилище реализована команда `gar_upload_dump`

--path
    Путь до файла с дампом. По умолчанию - /home/app/web/dumps/m3_gar_dump.back

--store_url
    URL хранилища. По умолчанию - https://cloud-api.yandex.net/v1/disk/resources

--upload_path
    Путь в хранилище, кудо нужно разместить файл. По умолчанию - gar/m3_gar_dump.back

Значения по умолчанию выставлены таким образом, чтобы запуск в контейнере мог быть сделан
без дополнительной передачи параметров при условии, что в переменной AUTH_TOKEN
установлен OAuth-токен авторизации в хранилище и в /home/app/web/dumps лежит
заранее снятый дамп ГАР



Заполнение полей name_with_parents в модели иерархий и полей name_with_typename в модели AddrOdj
================================================================================================

В БД были добавлены дополнительные поля name_with_parents (в модели иерархий) и name_with_typename (в модели AddrOdj).
Для заполнения данных полей данными предоставлена команда `fill_custom_fields`
Для нее доступны следующие параметры:

--parents
    Заполняем поля name_with_parents в модели иерархий, по умолчанию в муниципальной иерархии, можно указать ключи:
        --adm - поля заполняются для административной иерархии
        --guids - можно через запятую указать guid-ы объектов, для которых нужно заполнить поле
        --levels - можно через запятую указать уровни объектов, для которых нужно заполнить поле

--typenames
    Заполняем поля name_with_typename в модели AddrOdj для уровней 7 и 8 (улицы, микрорайоны, территории и т.д.)
        --guids_typenames - можно через запятую указать guid-ы объектов, для которых нужно заполнить поле

Примеры выполнения команды:

    - Обновление всех полей name_with_parents в модели муниципальной иерархии:

            python manage.py fill_custom_fields --parents

    - Обновление полей name_with_parents в модели муниципальной иерархии для уровней 1 и 2:

            python manage.py fill_custom_fields --parents --levels=1,2

    - Обновление всех полей name_with_typename в модели AddrObj:

            python manage.py fill_custom_fields --typenames

    - Обновление поля name_with_typename в модели AddrObj для объекта по guid:

            python manage.py fill_custom_fields --typenames --guids_typenames=6b87470a-ac30-418b-991b-3c0d42515192