
Согласие на обработку персональных данных в Django-проекте часто начинается с одного BooleanField. Но затем оказывается, что недостаточно помнить только факт нажатия на чекбокс: пользователь мог видеть другую редакцию документа, отозвать согласие, выбрать лишь часть категорий файлов cookie, а администратору может понадобиться журнал действий и выгрузка в CSV.
Я сделал для этого два полностью независимых Django-пакета с открытым исходным кодом: django-consent-152fz для юридически значимых согласий и django-cookies-152fz для политики файлов cookie, категорий, подключённых сервисов и окна выбора. В статье покажу реальную модель данных, минимальное подключение и то, как устроены редакции, журнал событий и выгрузка данных.
Ссылки на проекты:
Сразу обозначу границу ответственности. Это технические пакеты, а не юридическая гарантия соответствия 152-ФЗ. Они не заменяют юриста, не определяют за оператора состав персональных данных и не создают автоматически корректные документы.
Их задача — дать воспроизводимый серверный контур для документов, редакций, статусов, истории действий, пользовательского выбора файлов cookie и выгрузки данных.
Почему два пакета
Сначала согласия и файлы cookie выглядели как одна задача: пользователь что-то подтверждает, а сайт должен сохранить его выбор и историю.
Но в реальном проекте это два разных направления.
Согласие связано с целью обработки и юридическим документом. Например, пользователь оставляет заявку на курс, отправляет обращение через форму контактов или соглашается на рассылку.
Модуль файлов cookie связан с техническими категориями и подключёнными сервисами сайта: обязательными файлами cookie, аналитикой, маркетинговыми счётчиками, внешними виджетами и повторным запросом выбора после изменения политики.
Поэтому пакеты независимы:
pip install django-consent-152fzpip install django-cookies-152fz
При необходимости можно установить оба:
pip install django-consent-152fz django-cookies-152fz
Но это не обязательная связка.
django-cookies-152fz не требует django-consent-152fz, не импортирует его модели и не использует его жизненный цикл согласий. Политики файлов cookie, категории, реестр подключённых сервисов, окно выбора, пользовательские решения, журнал событий и выгрузка данных работают внутри cookie-модуля как самостоятельный контур.
Модель согласий: цель, документ, редакция, запись, события
В коде используется не абстрактная цепочка вида Consent → ConsentVersion → UserConsent, а конкретные сущности:
ConsentPurpose LegalDocument \ / \ / DocumentRevision | ConsentRecord | ConsentEvent
ConsentPurpose — цель обработки. Например: «обработать заявку на обучение» или «ответить на обращение через форму контактов».
LegalDocument — юридический документ как постоянный контейнер.
DocumentRevision — конкретная опубликованная редакция текста. Именно к ней привязывается согласие.
ConsentRecord — запись о текущем или историческом состоянии согласия конкретного субъекта.
ConsentEvent — неизменяемый журнал переходов: выдача, отзыв, устаревание, подтверждение и другие события.
Новая редакция документа не перезаписывает старую. Если текст изменился, создаётся новый DocumentRevision. Старый ConsentRecord остаётся связанным с тем текстом, который пользователь видел в момент подтверждения.
Практически это даёт ответ на два вопроса: какой документ и какую редакцию подтвердил пользователь — и как это состояние менялось дальше.
Модуль файлов cookie — не только окно с кнопкой «Принять»
Окно выбора файлов cookie обычно воспринимают как небольшой элемент интерфейса с кнопками «Принять» и «Настроить».
Но само окно — только внешняя часть процесса. В модуле отдельно существуют политика, настройки отображения и пользовательский выбор.
Состав и редакция политики
CookieCategory ← записи реестра cookie и подключённых сервисов \ / \ / CookiePolicyRevision
CookieCategory — справочник категорий. Например:
-
обязательные;
-
функциональные;
-
аналитические;
-
маркетинговые.
Реестр содержит сведения о конкретных файлах cookie и подключённых сервисах: сторонних скриптах, системах аналитики или виджетах.
Для каждой записи можно хранить поставщика, назначение, категорию, срок хранения, адрес подключаемого скрипта, имена файлов cookie, стратегию очистки и признак активности.
CookiePolicyRevision фиксирует опубликованную редакцию политики вместе со снимком категорий и реестра подключённых сервисов на момент публикации.
Так можно не ограничиваться общей формулировкой «сайт использует файлы cookie», а поддерживать технический учёт подключённых сервисов.
Настройки отображения и выбор пользователя
Параллельно существует отдельный контур интерфейса:
CookieBannerRevision | vCookieConsentRecord | vCookieConsentEvent
CookieBannerRevision отвечает за текст, кнопки, вид окна выбора, настройки выбора категорий, отображение на мобильных устройствах и другие параметры интерфейса.
CookieConsentRecord хранит итоговый выбор категорий конкретного пользователя или анонимного посетителя.
CookieConsentEvent фиксирует принятие, обновление выбора, устаревание и другие действия.
Политика и окно выбора версионируются отдельно. Это позволяет изменить текст кнопки или внешний вид окна, не смешивая изменение интерфейса с изменением состава подключённых сервисов и политики.
Если опубликована новая CookiePolicyRevision, предыдущие записи выбора не должны автоматически считаться выбором пользователя для нового набора категорий или новых внешних сервисов.
Минимальная установка
Пакеты включаются добавлением приложений в INSTALLED_APPS.
Для модуля согласий:
# settings.pyINSTALLED_APPS = [ # ... "django_consent_152fz",]
Для модуля файлов cookie:
# settings.pyINSTALLED_APPS = [ # ... "django_cookies_152fz",]
Настройки enable_core и enable_cookies сохранены для обратной совместимости. Для новой интеграции главный переключатель — наличие соответствующего приложения в INSTALLED_APPS.
Маршруты модуля согласий:
# urls.pyfrom django.urls import include, pathurlpatterns = [ path( "", include( ("django_consent_152fz.urls", "django_consent_152fz"), namespace="django_consent_152fz", ), ),]
Маршруты модуля файлов cookie:
# urls.pyfrom django.urls import include, pathurlpatterns = [ path( "cookies/", include( ("django_cookies_152fz.urls", "django_cookies_152fz"), namespace="django_cookies_152fz", ), ),]
Затем применяются миграции:
python manage.py migrate
Для демонстрационного проекта или быстрого ознакомления можно загрузить примеры:
python manage.py bootstrap_152fz_sample_documentspython manage.py bootstrap_152fz_cookie_defaults
В рабочем проекте вместо примеров создаются собственные цели обработки, юридические документы, редакции и реестр файлов cookie.
Как подключить сценарий получения согласия к форме
В демонстрационном приложении используется сценарий учебного центра: заявка на курс, обратная связь, регистрация и личный кабинет.
Для Django-формы можно использовать готовый ConsentCaptureModeMixin:
from django import formsfrom django_consent_152fz.forms import ConsentCaptureModeMixinclass ContactForm(ConsentCaptureModeMixin, forms.ModelForm): class Meta: model = ContactMessage fields = ("full_name", "email", "message")
Для каждого бизнес-сценария стоит заранее зафиксировать стабильные коды:
purpose_code + document_code + form_code
Например:
demo.contactdemo.course_signupdemo.certificate_request
Перед выполнением бизнес-действия проверяется статус согласия:
from django_consent_152fz import service_apiverification_context = { "channel": "form", "form_code": "demo.contact",}user = request.user if request.user.is_authenticated else Nonestatus_info = service_api.get_consent_status( purpose_code=purpose_code, document_code=document_code, user=user, anonymous_token=anonymous_token, verification_context=verification_context,)consent_required = bool(status_info.get("requires_consent"))
После успешной отправки формы и явного подтверждения пользователя создаётся запись согласия:
from django_consent_152fz import service_apifrom django_consent_152fz.core.models import ConsentRecordservice_api.accept_consent( purpose_code=purpose_code, document_code=document_code, user=user, anonymous_token=anonymous_token, confirmation_method=ConsentRecord.ConfirmationMethod.WEB_CHECKBOX, verification_context=verification_context, audit_context=build_request_audit_context( request, source="demo.contact.form", anonymous_token=anonymous_token, ),)
build_request_audit_context(...) здесь — вспомогательная функция проекта, которая собирает технические сведения HTTP-запроса для журнала действий.
Прикладной код не ищет вручную активную редакцию документа, не меняет статусы в обход правил и не реализует журналирование заново в каждой форме.
Для внешних подключений предусмотрен публичный программный интерфейс:
from django_consent_152fz import service_api
Основные операции:
service_api.get_consent_status(...)service_api.accept_consent(...)service_api.withdraw_consent(...)service_api.attach_anonymous_consents_to_user(...)
Окно выбора файлов cookie в шаблоне
Для модуля файлов cookie окно выбора подключается один раз в базовом шаблоне:
{% load cookies_tags %}{# ... основной шаблон сайта ... #}{% render_cookie_banner %}</body>
Но сам тег — только видимая часть. Необязательные скрипты должны быть описаны в реестре и привязаны к категориям, чтобы механизм модуля запускал их только после соответствующего выбора пользователя.
Иначе получится декоративное окно: кнопки есть, а аналитика и внешние скрипты уже успели загрузиться до действия пользователя.
Программный интерфейс для клиентских приложений уже есть
Для модуля согласий предусмотрен дополнительный программный интерфейс для одностраничных приложений и мобильных клиентов.
Он подключается отдельным набором зависимостей:
pip install "django-consent-152fz[api]"
Затем добавляется приложение:
INSTALLED_APPS = [ # ... "django_consent_152fz", "django_consent_152fz.api",]USE_API_152FZ = True
Дополнительная библиотека для программного интерфейса не является обязательной зависимостью ядра. Если она не нужна, базовый пакет остаётся легче.
Отдельно существует дополнительный контур подтверждённых и бумажных согласий:
INSTALLED_APPS = [ # ... "django_consent_152fz", "django_consent_152fz.verified_consents",]
Он нужен для сценариев, где подтверждения на сайте недостаточно и требуется загрузка или проверка подписанного документа.
Журнал событий и выгрузка
Одна из целей пакетов — не просто сохранить состояние, а сделать его пригодным для сопровождения.
В модуле согласий:
-
ConsentRecordотвечает на вопрос: какое состояние согласия сейчас; -
ConsentEventотвечает на вопрос: как система пришла к этому состоянию; -
ConsentModuleOperationAuditLogхранит действия в административной панели и программном слое; -
выбранные записи согласий и записи журнала операций можно выгружать в CSV.
В модуле файлов cookie:
-
CookieConsentRecordхранит итоговое состояние выбора категорий; -
CookieConsentEventхранит события выбора, обновления и устаревания; -
выбранные события можно выгружать в CSV;
-
разделитель CSV задаётся через административные настройки модуля.
Полезная практическая формула:
ConsentRecord: какое состояние у согласия сейчас?ConsentEvent: как система пришла к этому состоянию?
Стандартная административная панель Django используется намеренно. Для небольшого или среднего проекта отдельный интерфейс управления требованиями к обработке данных часто будет избыточным, а Django Admin уже даёт поиск, фильтры, разграничение доступа, действия над выбранными объектами и понятный интерфейс сопровождения.
Сценарий рассчитан прежде всего на просмотр и контроль истории. Исправление записей задним числом не должно быть штатной операцией.
Техническая совместимость
На момент публикации пакеты поддерживают:
-
Python 3.10–3.12;
-
Django 5.0–6.0;
-
лицензию MIT.
У модуля согласий ядро зависит только от Django. Дополнительный программный интерфейс подключается через [api], а ReportLab для формирования PDF-документов по сценариям подтверждённого или бумажного согласия — через [pdf].
Модуль файлов cookie остаётся независимым: для его установки, работы окна выбора, политики, реестра, журнала событий и выгрузок не требуются модуль согласий, дополнительный программный интерфейс или связанные с ними модели.
Чего пакеты не делают
Они не определяют:
-
какие персональные данные вправе собирать конкретный оператор;
-
какие цели обработки допустимы;
-
какой именно текст документа подходит для конкретного бизнеса;
-
какие организационные меры должны быть внедрены внутри компании;
-
когда требуется отдельное согласие и как оно должно быть юридически сформулировано.
Пакеты дают технический слой, чтобы согласованный процесс не остался набором чекбоксов в шаблонах и неясных полей в базе данных.
Дальнейшее развитие: подтверждённые согласия через «Госключ»
Для части сценариев обычного подтверждения на сайте достаточно. Но бывают ситуации, где оператору нужен более строгий порядок: сформировать документ по конкретной редакции, передать его пользователю на подписание и сохранить результат подписания вместе с историей согласия.
Одно из направлений развития — отдельная интеграция с приложением «Госключ».
Идея не в том, чтобы заменить обычные согласия на сайте электронной подписью. В большинстве пользовательских сценариев это было бы избыточно. Скорее речь о дополнительном режиме для случаев, где требуется подтверждённое подписание документа.
Технически такой контур мог бы работать так:
DocumentRevision ↓формирование неизменяемого документа ↓передача на подписание через «Госключ» ↓получение результата подписания ↓ConsentRecord + ConsentEvent + связанные файлы
В результате в записи согласия можно было бы хранить не только факт подтверждения в форме, но и сведения о подписанном документе, времени подписания, способе подтверждения и связанных результатах проверки.
Такую возможность разумно делать отдельным подключаемым приложением, а не частью базового модуля. Базовый django-consent-152fz должен оставаться пригодным для обычных сайтов без дополнительной инфраструктуры и сложного процесса подключения.
«Госключ» позволяет пользователям получать электронную подпись и подписывать электронные документы в приложении. Для организаций предусмотрен отдельный порядок подключения и программное взаимодействие, поэтому в рамках пакета это должно быть именно дополнительным, а не обязательным сценарием.
Что хотелось бы обсудить
Мне интересна обратная связь от Django-разработчиков, специалистов по защите информации, защите персональных данных и юристов, которые сталкивались с такими процессами в реальных проектах.
Особенно интересно узнать:
-
хватает ли текущего разделения на модуль согласий и модуль файлов cookie;
-
какие варианты выгрузки данных реально нужны чаще всего;
-
как удобнее встраивать сценарий получения согласия в многошаговые формы;
-
какие системы управления сайтами и внешние сервисы стоит поддержать в первую очередь;
-
насколько востребован отдельный контур подтверждённых согласий с подписанием через «Госключ»;
-
какие части документации нужны, чтобы внедрение в существующий Django-проект было проще.
Исходный код, демонстрационные проекты, русская и английская документация доступны в репозитории проекта.
ссылка на оригинал статьи https://habr.com/ru/articles/1049842/