Package: django-birdbath
Django BirdbathA simple tool for giving Django database data a good wash. Anonymise user data, delete stuff you don't need in your development environment, or whatever it is you need to do.UsageAddbirdbathto yourINSTALLED_APPSSetBIRDBATH_CHECKSandBIRDBATH_PROCESSORSas appropriate in your settings file (see Configuration below).Run./manage.py run_birdbathto trigger processors.Important! The default processors are destructive and will anonymise User emails and passwords. Do not run in production!By default, Birdbath enables aDjango system checkwhich will trigger an error if a Birdbath cleanup has not been triggered on the current environment.This is intended to give developers a hint that they need to anonymise/cleanup their data before running commands such asrunserver.The suggested approach is to setBIRDBATH_REQUIREDtoFalsein production environments using an environment variable.Checks can be skipped using the--skip-checksflag onrun_birdbathor by settingBIRDBATH_SKIP_CHECKS = Truein your Django settings.ConfigurationCommon SettingsBIRDBATH_REQUIRED(default:True) - if True, a Django system check will throw an error if anonymisation has not been executed. Set toFalsein your production environments.BIRDBATH_CHECKS- a list of paths to 'Check' classes to be executed before processors. If any of these returns False, the processors will refuse to run.BIRDBATH_PROCESSORS- a list of paths to 'Processor' classes to be executed to clean data.Processor Specific SettingsBIRDBATH_USER_ANONYMISER_EXCLUDE_EMAIL_RE(default:example\.com$) - A regex pattern which will be used to exclude users that match a certain email address when anonymising.BIRDBATH_USER_ANONYMISER_EXCLUDE_SUPERUSERS(default:True) - If True, users withis_superuserset to True will be excluded from anonymisation.Implementing your OwnYour site will probably have some of your own check/processor needs.ChecksCustom checks can be implemented by subclassingbirdbath.checks.BaseCheckand implementing thecheckmethod:from birdbath.checks import BaseCheck


class IsDirtyCheck(BaseCheck):
    def check(self):
        return os.environ.get("IS_DIRTY")Thecheckmethod should either returnTrueif the checks should continue, orFalseto stop checking and prevent processors from running.ProcessorsCustom processors can be implemented by subclassingbirdbath.processors.BaseProcessorand implementing therunmethod:from birdbath.processors import BaseProcessor


class DeleteAllMyUsersProcessor(BaseProcessor):
    def run(self):
        User.objects.all().delete()There are also more specialised base classes inbirdbath.processorsthat can help you write cleaner custom processors. For example, the above example could be written using theBaseModelDeleterclass instead:from birdbath.processors import BaseModelDeleter


class DeleteAllMyUsersProcessor(BaseModelDeleter):
    model = UserIf you only need to delete a subset of users, you can override theget_queryset()method, like so:from birdbath.processors import BaseModelDeleter


class DeleteNonStaffUsersProcessor(BaseModelDeleter):
    model = User

    def get_queryset(self):
        return super().get_queryset().filter(is_staff=False)If you're looking to 'anonymise' rather than delete objects, you will likely find theBaseModelAnonymiserclass useful. You just need to indicate the fields that should be 'anonymised' or 'cleared', and the class will do the rest. For example:from birdbath.processors import BaseModelAnonymiser


class UserAnonymiser(BaseModelAnonymiser):
    model = User

    # generate random replacement values for these fields
    anoymise_fields = ["first_name", "last_name", "email", "password"]


class CustomerProfileAnonymiser(BaseModelAnonymiser):
    model = CustomerProfile

    # generate random replacement values for these fields
    anoymise_fields = ["date_of_birth"]

    # set these fields to ``None`` (if supported), or a blank string
    clear_fields = ["email_consent", "sms_consent", "phone_consent", "organisation"]The class will generate:Valid but non-existent email addresses for fields usingdjango.db.models.EmailField.Random choice selections for any field withchoicesdefined at the field level.Historic dates for fields usingdjango.db.models.DateFieldordjango.db.models.DateTimeField.Random numbers for fields usingdjango.db.models.IntegerField(or one of it's subclasses),django.db.models.FloatFieldordjango.db.models.DecimalField.Real-looking first names for fields with one of the following names:"first_name","forename","given_name","middle_name".Real-looking last names for fields with one of the following names:"last_name","surname","family_name".Random strings for any other fields usingdjango.db.models.CharField,django.db.models.TextFieldor a subclass of those.If you have fields with custom validation requirements, or would simply like to generate more realistic replacement values, you can add 'generate' methods to your subclass to achieve this.BaseModelAnonymiserwill automatically look for method matching the format"generate_{field_name}"when anoymising field values. For example, the following processor will generate random values for "account_holder" and "account_number" fields:from birdbath.processors import BaseModelAnonymiser


class DirectDebitDeclarationAnonymiser(BaseModelAnonymiser):

    model = DirectDebitDeclaration
    anonymise_fields = ["account_holder", "account_number"]

    def generate_account_holder(self, field, obj):
        # Return a value to replace 'account_holder' field values
        # `field` is the field instance from the model
        # `obj` is the model instance being updated
        return self.faker.name()

    def generate_account_number(self, field, obj):
        # Return a value to replace 'account_number' field values
        # `field` is the field instance from the model
        # `obj` is the model instance being updated
        return self.faker.iban()Check/Processor ReferenceCheckschecks.contrib.heroku.HerokuNotProductionCheck- fails if theHEROKU_APP_NAMEenvironment variable is not set, or if it set and includes the wordproduction.checks.contrib.heroku.HerokuAnonymisationAllowedCheck- fails if theALLOWS_ANONYMISATIONenvironment variable does not match the name of the application.Processorsprocessors.users.UserEmailAnonymiser- replaces user email addresses with randomised addressesprocessors.users.UserPasswordAnonymiser- replaces user passwords with random UUIDsprocessors.contrib.wagtail.SearchQueryCleaner- removes the full search query historyprocessors.contrib.wagtail.FormSubmissionCleaner- removes all form submissions