File: how_bakery_behaves.md

package info (click to toggle)
python-model-bakery 1.20.5-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 532 kB
  • sloc: python: 4,298; sh: 149; makefile: 21
file content (134 lines) | stat: -rw-r--r-- 4,745 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# How Model Bakery behaves?

By default, Model Bakery skips fields with `null=True` or `blank=True`. Also if a field has a `default` value, it will be used.

You can override this behavior by:

1. Explicitly defining values

```python
# from "Basic Usage" page, assume all fields either null=True or blank=True
from model_bakery import baker

customer = baker.make('shop.Customer', enjoy_jards_macale=True, bio="A fan of Jards Malacé")
```

2. Passing `_fill_optional` with a list of fields to fill with random data

```python
customer = baker.make('shop.Customer', _fill_optional=['enjoy_jards_macale', 'bio'])
```

3. Passing `_fill_optional=True` to fill all fields with random data

```python
customer = baker.make('shop.Customer', _fill_optional=True)
```

## When shouldn't you let Baker generate things for you?

If you have fields with special validation, you should set their values by yourself.

Model Bakery should handle fields that:

1. don't matter for the test you're writing;
2. don't require special validation (like unique, etc);
3. are required to create the object.

## Currently supported fields

- `BooleanField`, `IntegerField`, `BigIntegerField`, `SmallIntegerField`, `PositiveIntegerField`, `PositiveBigIntegerField`, `PositiveSmallIntegerField`, `FloatField`, `DecimalField`
- `CharField`, `TextField`, `BinaryField`, `SlugField`, `URLField`, `EmailField`, `IPAddressField`, `GenericIPAddressField`, `ContentType`
- `ForeignKey`, `OneToOneField`, `ManyToManyField` (even with through model)
- `DateField`, `DateTimeField`, `TimeField`, `DurationField`
- `FileField`, `ImageField`
- `JSONField`, `ArrayField`, `HStoreField`
- `CICharField`, `CIEmailField`, `CITextField`
- `DecimalRangeField`, `IntegerRangeField`, `BigIntegerRangeField`, `DateRangeField`, `DateTimeRangeField`

Require `django.contrib.gis` in `INSTALLED_APPS`:

- `GeometryField`, `PointField`, `LineStringField`, `PolygonField`, `MultiPointField`, `MultiLineStringField`, `MultiPolygonField`, `GeometryCollectionField`

## Custom fields

Model Bakery allows you to define generators methods for your custom fields or overrides its default generators.
This can be achieved by specifying the field and generator function for the `generators.add` function.
It can also be done by specifying the field and generator function in the `BAKER_CUSTOM_FIELDS_GEN` setting.
Both can be the real python objects imported in settings or just specified as import path string.

Examples:

```python
from model_bakery import baker

def gen_func():
    return 'value'

baker.generators.add('test.generic.fields.CustomField', gen_func)
```

```python
# in the module code.path:
def gen_func():
    return 'value'

# in your tests.py file:
from model_bakery import baker

baker.generators.add('test.generic.fields.CustomField', 'code.path.gen_func')
```

```python
# in your settings.py file:
BAKER_CUSTOM_FIELDS_GEN = {
    'test.generic.fields.CustomField': 'code.path.gen_func',
}
```

## Customizing Baker

In some rare cases, you might need to customize the way Baker base class behaves.
This can be achieved by creating a new class and specifying it in your settings files. It is likely that you will want to extend Baker, however the minimum requirement is that the custom class have `make` and `prepare` functions.
In order for the custom class to be used, make sure to use the `model_bakery.baker.make` and `model_bakery.baker.prepare` functions, and not `model_bakery.baker.Baker` directly.

Examples:

```python
# in the module code.path:
class CustomBaker(baker.Baker):
    def get_fields(self):
        return [
            field
            for field in super(CustomBaker, self).get_fields()
            if not isinstance(field, CustomField)
        ]

# in your settings.py file:
BAKER_CUSTOM_CLASS = 'code.path.CustomBaker'
```

Additionally, if you want to your created instance to be returned respecting one of your custom ModelManagers, you can use the `_from_manager` parameter as the example below:

```python
movie = baker.make(Movie, title='Old Boys', _from_manager='availables')  # This will use the Movie.availables model manager
```

## Save method custom parameters

If you have overwritten the `save` method for a model, you can pass custom parameters to it using Model Bakery. Example:

```python
class ProjectWithCustomSave(models.Model):
    # some model fields
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL)

    def save(self, user, *args, **kwargs):
        self.created_by = user
        return super(ProjectWithCustomSave, self).save(*args, **kwargs)

#with model baker:
user = baker.make(settings.AUTH_USER_MODEL)
project = baker.make(ProjectWithCustomSave, _save_kwargs={'user': user})
assert user == project.user
```