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 replacers ---------------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