{"id":22196686,"url":"https://github.com/druids/django-gdpr","last_synced_at":"2025-06-20T04:05:19.757Z","repository":{"id":44910477,"uuid":"129723677","full_name":"druids/django-GDPR","owner":"druids","description":null,"archived":false,"fork":false,"pushed_at":"2023-09-20T13:01:05.000Z","size":281,"stargazers_count":58,"open_issues_count":5,"forks_count":15,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-06-20T04:03:17.809Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/druids.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-04-16T10:09:44.000Z","updated_at":"2023-12-11T00:00:46.000Z","dependencies_parsed_at":"2025-06-20T04:03:20.478Z","dependency_job_id":null,"html_url":"https://github.com/druids/django-GDPR","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/druids/django-GDPR","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/druids%2Fdjango-GDPR","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/druids%2Fdjango-GDPR/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/druids%2Fdjango-GDPR/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/druids%2Fdjango-GDPR/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/druids","download_url":"https://codeload.github.com/druids/django-GDPR/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/druids%2Fdjango-GDPR/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260878327,"owners_count":23075959,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-02T14:16:06.203Z","updated_at":"2025-06-20T04:05:14.744Z","avatar_url":"https://github.com/druids.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Django-GDPR [![Build Status](https://travis-ci.org/BrnoPCmaniak/django-GDPR.svg?branch=develop)](https://travis-ci.org/BrnoPCmaniak/django-GDPR)\n\nThis library enables you to store user's consent for data retention easily\nand to anonymize/deanonymize user's data accordingly.\n\nFor brief overview you can check example app in `tests` directory.\n\n# Quickstart\n\nInstall django-gdpr with pip:\n\n```bash\npip install django-gdpr\n```\n\nAdd gdpr to your `INSTALLED_APPS`:\n\n```python\nINSTALLED_APPS = [\n    # Django apps...\n    'gdpr',\n]\n```\n\nImagine having a customer model:\n\n```python\n# app/models.py\n\nfrom django.db import models\n\nfrom gdpr.mixins import AnonymizationModel\n\nclass Customer(AnonymizationModel):\n    # these fields will be used as basic keys for pseudoanonymization\n    first_name = models.CharField(max_length=256)\n    last_name = models.CharField(max_length=256)\n\n    birth_date = models.DateField(blank=True, null=True)\n    personal_id = models.CharField(max_length=10, blank=True, null=True)\n    phone_number = models.CharField(max_length=9, blank=True, null=True)\n    fb_id = models.CharField(max_length=256, blank=True, null=True)\n    last_login_ip = models.GenericIPAddressField(blank=True, null=True)\n```\n\nYou may want a consent to store all user's data for two years and consent to store first and last name for 10 years.\nFor that you can simply add new consent purposes like this.\n\n```python\n# app/purposes.py\n\nfrom dateutil.relativedelta import relativedelta\n\nfrom gdpr.purposes.default import AbstractPurpose\n\nGENERAL_PURPOSE_SLUG = \"general\"\nFIRST_AND_LAST_NAME_SLUG = \"first_and_last\"\n\nclass GeneralPurpose(AbstractPurpose):\n    name = \"Retain user data for 2 years\"\n    slug = GENERAL_PURPOSE_SLUG\n    expiration_timedelta = relativedelta(years=2)\n    fields = \"__ALL__\"  # Anonymize all fields defined in anonymizer\n\nclass FirstAndLastNamePurpose(AbstractPurpose):\n    \"\"\"Store First \u0026 Last name for 10 years.\"\"\"\n    name = \"retain due to internet archive\"\n    slug = FIRST_AND_LAST_NAME_SLUG\n    expiration_timedelta = relativedelta(years=10)\n    fields = (\"first_name\", \"last_name\")\n```\n\nThe field `fields` specify to which fields this consent applies to.\n\nSome more examples:\n```python\nfields = (\"first_name\", \"last_name\") # Anonymize only two fields\n\n# You can also add nested fields to anonymize fields on related objects.\nfields = (\n    \"primary_email_address\",\n    (\"emails\", (\n        \"email\",\n    )),\n)\n\n# Some more advanced configs may look like this:\nfields = (\n    \"__ALL__\",\n    (\"addresses\", \"__ALL__\"),\n    (\"accounts\", (\n        \"__ALL__\",\n        (\"payments\", (\n            \"__ALL__\",\n        ))\n    )),\n    (\"emails\", (\n        \"email\",\n    )),\n)\n\n```\n\nNow when we have the purpose(s) created we also have to make an _anonymizer_ so the library knows which fields to\nanonymize and how. This is fairly simple and is quite similar to Django forms.\n\n```python\n# app/anonymizers.py\n\nfrom gdpr import anonymizers\nfrom tests.models import Customer\n\n\nclass CustomerAnonymizer(anonymizers.ModelAnonymizer):\n    first_name = anonymizers.MD5TextFieldAnonymizer()\n    last_name = anonymizers.MD5TextFieldAnonymizer()\n    primary_email_address = anonymizers.EmailFieldAnonymizer()\n\n    birth_date = anonymizers.DateFieldAnonymizer()\n    personal_id = anonymizers.PersonalIIDFieldAnonymizer()\n    phone_number = anonymizers.PhoneFieldAnonymizer()\n    fb_id = anonymizers.CharFieldAnonymizer()\n    last_login_ip = anonymizers.IPAddressFieldAnonymizer()\n\n    class Meta:\n        model = Customer\n```\n\nNow you can fully leverage the system:\n\nYou can create/revoke consent:\n```python\nfrom gdpr.models import LegalReason\n\nfrom tests.models import Customer\nfrom tests.purposes import FIRST_AND_LAST_NAME_SLUG\n\n\ncustomer = Customer(first_name=\"John\", last_name=\"Smith\")\ncustomer.save()\n\n# Create consent\nLegalReason.objects.create_consent(FIRST_AND_LAST_NAME_SLUG, customer)\n\n# And now you can revoke it\nLegalReason.objects.deactivate_consent(FIRST_AND_LAST_NAME_SLUG, customer)\n```\n\nIn case your model uses the `AnonymizationModelMixin` or `AnonymizationModel` you can create and revoke consents even\neasier.\n```python\nfrom tests.models import Customer\nfrom tests.purposes import FIRST_AND_LAST_NAME_SLUG\n\n\ncustomer = Customer(first_name=\"John\", last_name=\"Smith\")\ncustomer.save()\n\n# Create consent\ncustomer.create_consent(FIRST_AND_LAST_NAME_SLUG)\n\n# And now you can revoke it\ncustomer.deactivate_consent(FIRST_AND_LAST_NAME_SLUG)\n```\n\n\nExpired consents are revoked by running the following command. You should invoke it repeatedly, for example by cron.\nThe invocation interval depends on your circumstances - how fast you want to expire consents after their revocation,\nthe amount of consents to expire in the interval, server load, and last but not least, legal requirements.\n\n```python\nfrom gdpr.models import LegalReason\n\nLegalReason.objects.expire_old_consents()\n```\n\n## FieldAnonymizers\n\n* `FunctionAnonymizer` - in place lambda/function anonymization method (e.g. `secret_code = anonymizers.FunctionFieldAnonymizer(lambda x: x**2)`)\n* `DateFieldAnonymizer`\n* `CharFieldAnonymizer`\n* `DecimalFieldAnonymizer`\n* `IPAddressFieldAnonymizer`\n* `CzechAccountNumberFieldAnonymizer` - for czech bank account numbers\n* `IBANFieldAnonymizer`\n* `JSONFieldAnonymizer`\n* `EmailFieldAnonymizer`\n* `MD5TextFieldAnonymizer`\n* `SHA256TextFieldAnonymizer`\n* `HashTextFieldAnonymizer` - anonymization using given hash algorithm (e.g. `secret_code = anonymizers.HashTextFieldAnonymizer('sha512')`)\n* `StaticValueFieldAnonymizer` - anonymization by replacing with static value (e.g. `secret_code = anonymizers.StaticValueFieldAnonymizer(42)`)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdruids%2Fdjango-gdpr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdruids%2Fdjango-gdpr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdruids%2Fdjango-gdpr/lists"}