Djenerator
Djenerator is a simple tool made to consistently generate test, random or dummy data from the model descriptions of Django. Djenerator has several advantages over other alternatives:
- Entry level is extremely easy, just install the package and include it in your project, there's no requirement by the user to specify the random data factory (it is optional).
- It generates data for dependent models (based on related fields), for example, if a model A has a
ForeignKey
to model B, then djenerator will recognize that generating data for model A requires having some instances of model B, and will generate them when necessary. - Generators can simultaneously satisfy many constraints, like the
unique
flag,null
flag,unique_together
constraints, or django field validators. - Easy to extend to include your own values for some of the fields.
- It can generate a big dump for a database at once, not only individual models.
Installation
- Using pip, you can install djenerator using this command:
$ pip3 install djenerator
- Add
'djenerator'
to yourINSTALLED_APPS
:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
# ...
'djenerator',
# ...
]
Usage
The generation of data can be done by a command using the manage.py
file in your project:
$ python3 manage.py jenerate app_name size
Equivalently, this can be done within python code
from djenerator import generate_test_data
generate_test_data(app_name, size)
To generate for specific models
$ python3 manage.py jenerate app_name size --models ModelA ModelB ...
Equivalently, this can be done within python code
from djenerator import generate_test_data
generate_test_data(app_name, size, models_cls=["ModelA", "ModelB"])
To allow some null values
By default, djenerator generates data for all fields even if null values are allowed. To allow some null values, allow the following option:
$ python3 manage.py jenerate app_name size --allow-null
Equivalently, this can be done within python code
from djenerator import generate_test_data
generate_test_data(app_name, size, allow_null=True)
Writing your custom generators
You can add a customized values generator for a some fields in some models.
This will most likely be required if you are writing your own validators.
Writing your customized generator, can be done by adding a class to the module {app_name}.test_data
:
- Write a class with the same name as the model.
- For the fields to write a custom generator, write an attirbute with a matching name, with the generator as a value.
The generator is either a function with no any required arguments that generates random values, or can also be an iterable of all possible values.
As an example, in an app testapp
, if testapp/models.py
is:
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _
def validate_mod91(value):
if value % 91 != 0:
raise ValidationError(
_('%(value)s is not an even number'), params={'value': value},
)
class TestModel(models.Model):
field1 = models.CharField(max_length=256)
field2 = models.BigIntegerField(validators=[validate_mod91])
field3 = models.IntegerField()
class Meta:
unique_together = (('field1', 'field2'),)
then testapp/test_data.py
will contain the following:
import random
class TestModel:
field2 = lambda: random.randint(1, 1000) * 91
field3 = list(range(10000))
The value generator does not necessarily need to always generate unique or valid values, however, it should generate them with high probability.
In the example above, the validate_mod91
checks if a number is divisible by 91, two bad generators can be:
-
lambda: random.randint(0, 100000)
will generate valid values but with only 1% chance; however, a chance higher than 20% or even 50% would be much better. -
lambda: random.randint(0, 10) * 91
will generate only 11 unique valid values; however, it is recommended to return a factor higher than the total number of models to be generated (especially if there areunique
or manyunique_together
constraints).
Running the tests
Run the tests by running the command:
$ python3 manage.py test
The following combinations are tested:
Django | Python | Status |
---|---|---|
1.10.8 | 3.5 | |
1.11.29 | 3.5 | |
1.11.29 | 3.6 | |
1.11.29 | 3.7 | |
2.2.28 | 3.5 | |
2.2.28 | 3.6 | |
2.2.28 | 3.7 | |
3.2.15 | 3.6 | |
3.2.15 | 3.7 | |
4.0.7 | 3.8 | |
4.0.7 | 3.9 | |
4.1.1 | 3.8 | |
4.1.1 | 3.9 |
Requirements
-
django >= 1.10
. -
pytz
is required to be manually installed fordjango < 1.11
, otherwise it is installed by django when it is required (it is not required for some higher versions of django). -
pillow
if ImageFields are used, we don't require it be default, but django will.
Our setup requires only django
, other packages are reported by django.