• Get Review Board
  • What's New
  • Products
  • Review Board Code review, image review, and document review
  • Documentation
  • Release Notes
  • Power Pack Enterprise integrations, reports, and enhanced document review
  • Try for 60 Days
  • Purchase
  • RBCommons Review Board as a Service, hosted by us
  • Pricing
  • RBTools Command line tools and Python API for Review Board
  • Documentation
  • Release Notes
  • Review Bot Automated code review, connecting tools you already use
  • Documentation
  • Release Notes
  • RB Gateway Manage Git and Mercurial repositories in your network
  • Documentation
  • Release Notes
  • Learn and Explore
  • What is Code Review?
  • Documentation
  • Frequently Asked Questions
  • Support Options
  • Third-Party Integrations
  • Demo
  • Review Board RBTools Power Pack Review Bot Djblets RB Gateway
    1. Djblets 5.x
    2. Version 5.x
    3. Version 4.x
    4. Version 3.x
    5. Version 2.x
    6. Version 2.0
    7. Version 1.0
    8. Version 0.9
    9. Djblets Documentation
    10. Guides
    11. Privacy Compliance Guides
    12. Getting and Checking Consent
  • Home
  • Guides
  • Avatar Services Guides
  • Writing Avatar Services
  • Extension Guides
  • Writing Extensions
  • Testing Extensions
  • Feature Checks Guides
  • Introduction to Feature Checks
  • Writing Features
  • Writing Feature Checkers
  • Testing with Feature Checks
  • Integration Guides
  • Supporting Integrations
  • Writing Integrations
  • Privacy Compliance Guides
  • Getting and Checking Consent
  • Working with Personally Identifiable Information
  • Service Integrations
  • reCAPTCHA Guides
  • Using reCAPTCHA
  • Registries Guides
  • Writing Registries
  • Web API Guides
  • Writing Web API Resources
  • Adding OAuth2 Support
  • Module and Class References
  • djblets
  • djblets.deprecation
  • djblets.auth.forms
  • djblets.auth.ratelimit
  • djblets.auth.signals
  • djblets.auth.util
  • djblets.auth.views
  • djblets.avatars.errors
  • djblets.avatars.forms
  • djblets.avatars.registry
  • djblets.avatars.services
  • djblets.avatars.services.base
  • djblets.avatars.services.fallback
  • djblets.avatars.services.file_upload
  • djblets.avatars.services.gravatar
  • djblets.avatars.services.url
  • djblets.avatars.settings
  • djblets.cache.backend
  • djblets.cache.backend_compat
  • djblets.cache.context_processors
  • djblets.cache.errors
  • djblets.cache.forwarding_backend
  • djblets.cache.serials
  • djblets.cache.synchronizer
  • djblets.conditions
  • djblets.conditions.choices
  • djblets.conditions.conditions
  • djblets.conditions.errors
  • djblets.conditions.operators
  • djblets.conditions.values
  • djblets.configforms.forms
  • djblets.configforms.mixins
  • djblets.configforms.pages
  • djblets.configforms.registry
  • djblets.configforms.views
  • djblets.datagrid.grids
  • djblets.db.backends.mysql.base
  • djblets.db.fields
  • djblets.db.fields.base64_field
  • djblets.db.fields.comma_separated_values_field
  • djblets.db.fields.counter_field
  • djblets.db.fields.json_field
  • djblets.db.fields.modification_timestamp_field
  • djblets.db.fields.relation_counter_field
  • djblets.db.managers
  • djblets.db.query
  • djblets.db.query_catcher
  • djblets.db.query_comparator
  • djblets.db.validators
  • djblets.extensions.admin
  • djblets.extensions.errors
  • djblets.extensions.extension
  • djblets.extensions.forms
  • djblets.extensions.hooks
  • djblets.extensions.loaders
  • djblets.extensions.manager
  • djblets.extensions.middleware
  • djblets.extensions.models
  • djblets.extensions.packaging
  • djblets.extensions.resources
  • djblets.extensions.settings
  • djblets.extensions.signals
  • djblets.extensions.staticfiles
  • djblets.extensions.testing
  • djblets.extensions.testing.testcases
  • djblets.extensions.urls
  • djblets.extensions.views
  • djblets.extensions.templatetags.djblets_extensions
  • djblets.features
  • djblets.features.checkers
  • djblets.features.decorators
  • djblets.features.errors
  • djblets.features.feature
  • djblets.features.level
  • djblets.features.registry
  • djblets.features.testing
  • djblets.features.templatetags.features
  • djblets.forms.fields
  • djblets.forms.fieldsets
  • djblets.forms.forms
  • djblets.forms.forms.key_value_form
  • djblets.forms.widgets
  • djblets.gravatars
  • djblets.gravatars.templatetags.gravatars
  • djblets.http.middleware
  • djblets.http.responses
  • djblets.integrations.errors
  • djblets.integrations.forms
  • djblets.integrations.hooks
  • djblets.integrations.integration
  • djblets.integrations.manager
  • djblets.integrations.mixins
  • djblets.integrations.models
  • djblets.integrations.urls
  • djblets.integrations.views
  • djblets.log
  • djblets.log.middleware
  • djblets.log.siteconfig
  • djblets.log.urls
  • djblets.log.views
  • djblets.mail.dmarc
  • djblets.mail.message
  • djblets.mail.testing
  • djblets.mail.utils
  • djblets.markdown
  • djblets.markdown.extensions.escape_html
  • djblets.markdown.extensions.wysiwyg
  • djblets.markdown.extensions.wysiwyg_email
  • djblets.pipeline.compilers.es6
  • djblets.pipeline.compilers.less
  • djblets.pipeline.compilers.mixins
  • djblets.pipeline.compilers.rollup
  • djblets.pipeline.compilers.typescript
  • djblets.pipeline.settings
  • djblets.privacy.consent
  • djblets.privacy.consent.base
  • djblets.privacy.consent.common
  • djblets.privacy.consent.errors
  • djblets.privacy.consent.forms
  • djblets.privacy.consent.hooks
  • djblets.privacy.consent.registry
  • djblets.privacy.consent.tracker
  • djblets.privacy.models
  • djblets.privacy.pii
  • djblets.privacy.templatetags.djblets_privacy
  • djblets.recaptcha.mixins
  • djblets.recaptcha.siteconfig
  • djblets.recaptcha.templatetags.djblets_recaptcha
  • djblets.recaptcha.widgets
  • djblets.registries
  • djblets.registries.errors
  • djblets.registries.importer
  • djblets.registries.mixins
  • djblets.registries.registry
  • djblets.registries.signals
  • djblets.secrets
  • djblets.secrets.crypto
  • djblets.secrets.token_generators
  • djblets.secrets.token_generators.base
  • djblets.secrets.token_generators.legacy_sha1
  • djblets.secrets.token_generators.registry
  • djblets.secrets.token_generators.vendor_checksum
  • djblets.siteconfig
  • djblets.siteconfig.admin
  • djblets.siteconfig.context_processors
  • djblets.siteconfig.django_settings
  • djblets.siteconfig.forms
  • djblets.siteconfig.managers
  • djblets.siteconfig.middleware
  • djblets.siteconfig.models
  • djblets.siteconfig.signals
  • djblets.siteconfig.views
  • djblets.template.caches
  • djblets.template.context
  • djblets.template.loaders.conditional_cached
  • djblets.template.loaders.namespaced_app_dirs
  • djblets.testing.decorators
  • djblets.testing.testcases
  • djblets.testing.testrunners
  • djblets.urls.context_processors
  • djblets.urls.decorators
  • djblets.urls.patterns
  • djblets.urls.resolvers
  • djblets.urls.root
  • djblets.urls.staticfiles
  • djblets.util.compat.django.core.cache
  • djblets.util.compat.python.past
  • djblets.util.contextmanagers
  • djblets.util.dates
  • djblets.util.decorators
  • djblets.util.filesystem
  • djblets.util.functional
  • djblets.util.html
  • djblets.util.http
  • djblets.util.humanize
  • djblets.util.json_utils
  • djblets.util.properties
  • djblets.util.serializers
  • djblets.util.symbols
  • djblets.util.templatetags.djblets_deco
  • djblets.util.templatetags.djblets_email
  • djblets.util.templatetags.djblets_forms
  • djblets.util.templatetags.djblets_images
  • djblets.util.templatetags.djblets_js
  • djblets.util.templatetags.djblets_utils
  • djblets.util.typing
  • djblets.util.views
  • djblets.views.generic.base
  • djblets.views.generic.etag
  • djblets.webapi.auth
  • djblets.webapi.auth.backends
  • djblets.webapi.auth.backends.api_tokens
  • djblets.webapi.auth.backends.base
  • djblets.webapi.auth.backends.basic
  • djblets.webapi.auth.backends.oauth2_tokens
  • djblets.webapi.auth.views
  • djblets.webapi.decorators
  • djblets.webapi.encoders
  • djblets.webapi.errors
  • djblets.webapi.fields
  • djblets.webapi.managers
  • djblets.webapi.models
  • djblets.webapi.oauth2_scopes
  • djblets.webapi.resources
  • djblets.webapi.resources.base
  • djblets.webapi.resources.group
  • djblets.webapi.resources.registry
  • djblets.webapi.resources.root
  • djblets.webapi.resources.user
  • djblets.webapi.resources.mixins.api_tokens
  • djblets.webapi.resources.mixins.forms
  • djblets.webapi.resources.mixins.oauth2_tokens
  • djblets.webapi.resources.mixins.queries
  • djblets.webapi.responses
  • djblets.webapi.signals
  • djblets.webapi.testing
  • djblets.webapi.testing.decorators
  • djblets.webapi.testing.testcases
  • General Index
  • Python Module Index
  • Release Notes
  • Getting and Checking Consent¶

    If your application passes a user’s personal information (such as PII) to third-party services, it’s often good to get the user’s consent (and for EU users protected by the GDPR, it may be legally required). This consent may be needed for two features, or for a dozen, and if you’re making use of extensions, there may be even more things that need consent.

    Djblets provides a djblets.privacy.consent module for registering things that require consent, for checking on whether consent was given, for providing UI for consent management, and for auditing the consent choices made by the user over time in a safe and secure way.

    Consent Requirements¶

    BaseConsentRequirement is the main class that everything else centers around. Subclasses define a requirement with a unique ID and information about what requires consent, primarily for display purposes.

    Any part of a codebase requiring consent will construct an instance of this class (or a subclass of it) and register it in the ConsentRequirementsRegistry (accessible through get_consent_requirements_registry().

    This looks like:

    from djblets.privacy.consent import (BaseConsentRequirement,
                                         get_consent_requirements_registry)
    
    
    class MyConsentRequirement(BaseConsentRequirement):
        requirement_id = 'my-requirement-id'
        name = 'My Requirement'
    
        intent_description = (
            'A description about the requirement, presented to the user '
            'clearly and informatively.'
        )
    
        data_use_description = (
            'A brief summary of what data gets sent to the data processor '
            'service.'
        )
    
        icons = {
            '1x': '/path/to/logo.png',
            '2x': '/path/to/logo@2x.png',
        }
    
    my_requirement = MyConsentRequirement()
    get_consent_requirements_registry().register(my_requirement)
    

    These requirements can be checked for consent to determine if consent was granted, denied, or not yet decided upon:

    from djblets.privacy.consent import Consent
    
    ...
    
    consent = my_requirement.get_consent(user)
    
    if consent == Consent.GRANTED:
        ...
    elif consent == Consent.DENIED:
        ...
    elif consent == Consent.UNSET:
        ...
    

    Tracking Consent Decisions¶

    A decision made on a consent requirement is represented as a ConsentData instance, tracked by a BaseConsentTracker.

    ConsentData stores whether a given BaseConsentRequirement ID has been granted or denied, along with additional data for audit purposes: The consent decision’s timestamp, source location (which can be a URL or some other identifier), and custom application-provided metadata.

    The consent tracker (accessible via get_consent_tracker()) tracks that consent, recording it for later audits. It stores the data along with an identifier that maps to the user (defaults to a SHA256 hash of their e-mail address).

    The default consent tracker uses the database (storing in the StoredConsentData model), but applications can change how consent is stored and looked up by subclassing the base tracker and setting settings.DJBLETS_PRIVACY_CONSENT_TRACKER to its full module/class path.

    If using the built-in UI, much of this happens behind the scenes. If you need to record consent directly, you can use record_consent_data_list().

    from django.utils import timezone
    from djblets.privacy.consent import get_consent_tracker
    
    ...
    
    now = timezone.now()
    
    get_consent_tracker().record_consent_data_list(
        user,
        [
            my_requirement_1.build_consent_data(
                granted=True,
                timestamp=now,
                source='https://example.com/accounts/consent/'),
            my_requirement_2.build_consent_data(
                granted=False,
                timestamp=now,
                source='https://example.com/accounts/consent/'),
        ])
    

    Or to get all the consent decisions filed by a user (for display in the UI, for example), use get_all_consent().

    from django.utils import six, timezone
    from djblets.privacy.consent import get_consent_tracker
    
    ...
    
    now = timezone.now()
    
    all_consent = get_consent_tracker().get_all_consent(user)
    
    if my_requirement_1.requirement_id in all_consent:
        if all_consent[my_requirement_1.requirement_id] == Consent.GRANTED:
           ...
        elif all_consent[my_requirement_1.requirement_id] == Consent.DENIED:
           ...
    

    Requiring Consent Decisions¶

    If you are using consent tracking, you will likely want to gate certain views that require the user to have made consent decisions. We provide a decorator for functional views and a mixin for class-style views. If the viewing user is authenticated and has any pending consent requirements, they will be redirected to the URL specified in settings.DJBLETS_PRIVACY_PENDING_CONSENT_REDIRECT_URL.

    This setting can also be a function, in which case it accepts the current HttpRequest.

    from django.http import HttpResponse
    from django.views.generic.base import View
    from djblets.privacy.consent.views import (CheckPendingConsentMixin,
                                               check_pending_consent)
    from djblets.views.generic.base import PrePostDispatchViewMixin
    
    
    class SimpleView(CheckPendingConsentMixin, PrePostDispatchViewMixin, View):
        def get(self, request, **kwargs):
            return HttpResponse('You have no pending consent requirements.')
    
    
    @check_pending_consent
    def simple_view(request):
         return HttpResponse('You have no pending consent requirements.')
    

    Keep up with the latest Review Board releases, security updates, and helpful information.

    About
    News
    Demo
    RBCommons Hosting
    Integrations
    Happy Users
    Support Options
    Documentation
    FAQ
    User Manual
    RBTools
    Administration Guide
    Power Pack
    Release Notes
    Downloads
    Review Board
    RBTools
    Djblets
    Power Pack
    Package Store
    PGP Signatures
    Contributing
    Bug Tracker
    Submit Patches
    Development Setup
    Wiki
    Follow Us
    Mailing Lists
    Reddit
    Twitter
    Mastodon
    Facebook
    YouTube

    Copyright © 2006-2025 Beanbag, Inc. All rights reserved.

    Terms of Service — Privacy Policy — AI Ethics Policy — Branding

    On this page

    • [Top]
    • Consent Requirements
    • Tracking Consent Decisions
    • Requiring Consent Decisions