Library for GDPR implementation
Project description
Django-GDPR
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 numbersIBANFieldAnonymizer
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)
)
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for skip-django-GDPR-0.2.23.2.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | f91179b62591109311adb1e044455794f7239c566d02dd53087b63984d76fe01 |
|
MD5 | 2d028040409672ec61e20c78da322b80 |
|
BLAKE2b-256 | 414ad93231b171fecf68e94c6749070cd3703f1622aae41a47073b25561acc6c |
Hashes for skip_django_GDPR-0.2.23.2-py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a0146bd208947c2144d1dd3201c0708ec77b0d31458eaacf08d6674b22c36c52 |
|
MD5 | 4a162ed9843eabe7690ca2246840a396 |
|
BLAKE2b-256 | 7cb480a951ba04dadb96b99bae7a95a8aec40e7ad7a46f4c211d990dcf26e6a0 |