A module to help you faking a full django Django application database.
It provides:
- A base class ModelFaker that you can implement and associate to a Django Model to describe how to fake it
- Basic replacers (you can easily extend), to replace database data by simple or built fake data
- A dependency management to play fakers in the order you need
- Signals, to do things you need before or after model faking
Install:
pip install https://github.com/fle/django-db-faker/archive/0.1.tar.gz
Add djfaker
to your INSTALLED_APPS
:
# settings.py INSTALLED_APPS = ( ... 'djfaker', )
Here is an example of a basic app app_bank
:
* A Person
owns an Account
, idenfified by a numero
* An Account
marked as closed
is quite obsolete
#models.py class Person(models.Model): lastname = models.CharField(max_length=100) city = models.CharField(max_length=100) class Account(models.Model): person = models.ForeignKey(Person, on_delete=models.PROTECT, related_name='accounts') numero = models.IntegerField(unique=True) closed = BooleanField(default=False)
We want to anonymize (change confidential data) and simplify this database while keeping a consistent structure:
* Change Person.lastname
* Change Account.numero
* Remove Persons without account
* Remove Accounts marked as closed
Add a fakers.py in you app to replace basic properties
# fakers.py from djfaker import replacers class PersonFaker(ModelFaker): FAKER_FOR = models.Person lastname = replacers.ChoiceReplacer(choices=['Adams', 'Doe', 'Clayton', ...]) class AccountFaker(ModelFaker): FAKER_FOR = models.Person numero = replacers.SerialReplacer()
Use QS_FOR_DELETION
to delete accounts marked as closed
and persons without account:
class PersonFaker(ModelFaker): FAKER_FOR = models.Person QS_FOR_DELETION = lambda x: Person.objects.filter(accounts__isnull=True) numero = replacers.SerialReplacer() class AccountFaker(ModelFaker): FAKER_FOR = models.Person QS_FOR_DELETION = lambda x: Account.objects.filter(closed=True) numero = replacers.SerialReplacer()
Use DEPENDS_ON
to delete closed accounts before deleting persons without account:
class PersonFaker(ModelFaker): FAKER_FOR = models.Person QS_FOR_DELETION = lambda x: Person.objects.filter(accounts__isnull=True) DEPENDS_ON = ('app_bank.fakers.AccountFaker', ) numero = replacers.SerialReplacer() class AccountFaker(ModelFaker): FAKER_FOR = models.Person QS_FOR_DELETION = lambda x: Account.objects.filter(closed=True) numero = replacers.SerialReplacer()
Run provided command to fake this app:
# Simple usage ./manage.py faker_fake_db
A few options are available here
# Fake only a given app ./manage.py faker_fake_db app_bank # Fake only a given model ./manage.py faker_fake_db app_bank.PersonFaker # Fake only a given model and do not take care of dependencies ./manage.py faker_fake_db app_bank.PersonFaker --no-deps # Fake only a given model and do not run deletions ./manage.py faker_fake_db app_bank.AccountFaker --no-deps --no-dels
When data faking break a unicity constraint, script retry (quite stupidly) to fake instance. A setting is available allows to limit number of tries
DJFAKER_MAX_TRIES = 2 # default 3
You can simply give a builtin type (int, boolean, string, ...) value which will be set for each instance
class PersonFaker(ModelFaker): city = "Nantes"
djfaker provides 2 types of replacer:
* Simple replacers: which are not dependent of the instance other fields (played first).
They just inherit from SimpleReplacer
implement a method apply
.
Example:
class SimpleReplacer(BaseReplacer): def apply(self): raise NotImplementedError class ChoiceReplacer(SimpleReplacer): choices = [] def __init__(self, choices=None): if choices: self.choices = choices def apply(self): return choice(self.choices)
- Lazy replacers: which are dependent of the instance other fields (played last).
They inherit from LazyReplacer
implement a method apply
. tokens
must be attributes names of model you wan to fake.
Method apply
take instance as an argument.
Example:
tokens
must be attribute names of Example:
class LazyReplacer(BaseReplacer): tokens = [] def __init__(self, tokens=None): if tokens: self.tokens = tokens def apply(self, instance): raise NotImplementedError class LazyUsernameReplacer(LazyReplacer): tokens = [] def __init__(self, tokens=None): if tokens: self.tokens = tokens def apply(self, instance): return '{0}.{1}'.format( slugify(getattr(instance, self.tokens[0])), slugify(getattr(instance, self.tokens[1])))
You can easily extend them both and create your own replacer in few lines.
Don't do this in production :) !
You can adapt you settings to add djfaker
to your INSTALLED_APPS
only
on a development or test instance for more security.
# settings.py USE_DJFAKER = False INSTALLED_APPS = ( ... ) try: from localsettings import * except ImportError: pass if USE_DJFAKER: INSTALLED_APPS += ('djfaker', )
# localsettings.py USE_DJFAKER = True