Skip to main content

Django-GDPR Build Status

This library enables you to store user's consent for data retention easily and to anonymize/deanonymize user's data accordingly.

For brief overview you can check example app in tests directory.

Quickstart

Install django-gdpr with pip:

pip install skip-django-gdpr

Add gdpr to your INSTALLED_APPS:

INSTALLED_APPS = [
    # Django apps...
    'gdpr',
]

Imagine having a customer model:

# app/models.py

from django.db import models

from gdpr.mixins import AnonymizationModel

class Customer(AnonymizationModel):
    # these fields will be used as basic keys for pseudoanonymization
    first_name = models.CharField(max_length=256)
    last_name = models.CharField(max_length=256)

    birth_date = models.DateField(blank=True, null=True)
    personal_id = models.CharField(max_length=10, blank=True, null=True)
    phone_number = models.CharField(max_length=9, blank=True, null=True)
    fb_id = models.CharField(max_length=256, blank=True, null=True)
    last_login_ip = models.GenericIPAddressField(blank=True, null=True)

You may want a consent to store all user's data for two years and consent to store first and last name for 10 years. For that you can simply add new consent purposes like this.

# app/purposes.py

from dateutil.relativedelta import relativedelta

from gdpr.purposes.default import AbstractPurpose

GENERAL_PURPOSE_SLUG = "general"
FIRST_AND_LAST_NAME_SLUG = "first_and_last"

class GeneralPurpose(AbstractPurpose):
    name = "Retain user data for 2 years"
    slug = GENERAL_PURPOSE_SLUG
    expiration_timedelta = relativedelta(years=2)
    fields = "__ALL__"  # Anonymize all fields defined in anonymizer

class FirstAndLastNamePurpose(AbstractPurpose):
    """Store First & Last name for 10 years."""
    name = "retain due to internet archive"
    slug = FIRST_AND_LAST_NAME_SLUG
    expiration_timedelta = relativedelta(years=10)
    fields = ("first_name", "last_name")

The field fields specify to which fields this consent applies to.

Some more examples:

fields = ("first_name", "last_name") # Anonymize only two fields

# You can also add nested fields to anonymize fields on related objects.
fields = (
    "primary_email_address",
    ("emails", (
        "email",
    )),
)

# Some more advanced configs may look like this:
fields = (
    "__ALL__",
    ("addresses", "__ALL__"),
    ("accounts", (
        "__ALL__",
        ("payments", (
            "__ALL__",
        ))
    )),
    ("emails", (
        "email",
    )),
)

Now when we have the purpose(s) created we also have to make an anonymizer so the library knows which fields to anonymize and how. This is fairly simple and is quite similar to Django forms.

# app/anonymizers.py

from gdpr import anonymizers
from tests.models import Customer


class CustomerAnonymizer(anonymizers.ModelAnonymizer):
    first_name = anonymizers.MD5TextFieldAnonymizer()
    last_name = anonymizers.MD5TextFieldAnonymizer()
    primary_email_address = anonymizers.EmailFieldAnonymizer()

    birth_date = anonymizers.DateFieldAnonymizer()
    personal_id = anonymizers.PersonalIIDFieldAnonymizer()
    phone_number = anonymizers.PhoneFieldAnonymizer()
    fb_id = anonymizers.CharFieldAnonymizer()
    last_login_ip = anonymizers.IPAddressFieldAnonymizer()

    class Meta:
        model = Customer

Now you can fully leverage the system:

You can create/revoke consent:

from gdpr.models import LegalReason

from tests.models import Customer
from tests.purposes import FIRST_AND_LAST_NAME_SLUG


customer = Customer(first_name="John", last_name="Smith")
customer.save()

# Create consent
LegalReason.objects.create_consent(FIRST_AND_LAST_NAME_SLUG, customer)

# And now you can revoke it
LegalReason.objects.deactivate_consent(FIRST_AND_LAST_NAME_SLUG, customer)

In case your model uses the AnonymizationModelMixin or AnonymizationModel you can create and revoke consents even easier.

from tests.models import Customer
from tests.purposes import FIRST_AND_LAST_NAME_SLUG


customer = Customer(first_name="John", last_name="Smith")
customer.save()

# Create consent
customer.create_consent(FIRST_AND_LAST_NAME_SLUG)

# And now you can revoke it
customer.deactivate_consent(FIRST_AND_LAST_NAME_SLUG)

Expired consents are revoked by running the following command. You should invoke it repeatedly, for example by cron. The invocation interval depends on your circumstances - how fast you want to expire consents after their revocation, the amount of consents to expire in the interval, server load, and last but not least, legal requirements.

from gdpr.models import LegalReason

LegalReason.objects.expire_old_consents()

FieldAnonymizers

  • FunctionAnonymizer - in place lambda/function anonymization method (e.g. secret_code = anonymizers.FunctionFieldAnonymizer(lambda x: x**2))
  • DateFieldAnonymizer
  • CharFieldAnonymizer
  • DecimalFieldAnonymizer
  • IPAddressFieldAnonymizer
  • CzechAccountNumberFieldAnonymizer - for czech bank account numbers
  • IBANFieldAnonymizer
  • JSONFieldAnonymizer
  • EmailFieldAnonymizer
  • MD5TextFieldAnonymizer
  • SHA256TextFieldAnonymizer
  • HashTextFieldAnonymizer - anonymization using given hash algorithm (e.g. secret_code = anonymizers.HashTextFieldAnonymizer('sha512'))
  • StaticValueFieldAnonymizer - anonymization by replacing with static value (e.g. secret_code = anonymizers.StaticValueFieldAnonymizer(42))

Metadata

Release files for skip-django-GDPR 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for skip-django-GDPR 1.1.0
File Size Uploaded
skip_django_gdpr-1.1.0.tar.gz 55.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for skip-django-GDPR 1.1.0
File Interpreter ABI Platform
skip_django_gdpr-1.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 128.5 kB

Release files / skip_django_gdpr-1.1.0.tar.gz

Download URL skip_django_gdpr-1.1.0.tar.gz
Size 55.2 kB
Tags Source
SHA-256 checksum
How to use checksums
c7440da89089d6d765e2d1f472cf1ce1729304e6f792986bbbb774410802d1e8
BLAKE2b-256 checksum
How to use checksums
509802293ea65a93e56a8fe2012d883739e710845d4ea3ffb810197d3a2da211
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / skip_django_gdpr-1.1.0-py3-none-any.whl

Download URL skip_django_gdpr-1.1.0-py3-none-any.whl
Size 73.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7007f8bbca4d41228525f3c280b48dd2efcf83619fa71fba3349f58b8e3efbac
BLAKE2b-256 checksum
How to use checksums
04a0f2aa69e2b6827f4e2f0f4df7744a6fa54fd3ca257b63c434da0324391a74
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files

1.0.0

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page