File: fields.md

package info (click to toggle)
strawberry-graphql-django 0.62.0-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 1,968 kB
  • sloc: python: 27,530; sh: 17; makefile: 16
file content (193 lines) | stat: -rw-r--r-- 6,142 bytes parent folder | download
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
---
title: Defining Fields
---

# Defining Fields

> [!TIP]
> It is highly recommended to enable the [Query Optimizer Extension](optimizer.md)
> for improved performance and avoid some common pitfalls (e.g. the `n+1` issue)

Fields can be defined manually or `auto` type can be used for automatic type resolution. All basic field types and relation fields are supported out of the box. If you use a library that defines a custom field you will need to define an equivalent type such as `str`, `float`, `bool`, `int` or `id`.

```python title="types.py"
import strawberry_django
from strawberry import auto

@strawberry_django.type(models.Fruit)
class Fruit:
    id: auto
    name: auto

# equivalent type, inferred by `strawberry`

@strawberry_django.type(models.Fruit)
class Fruit2:
    id: strawberry.ID
    name: str
```

> [!TIP]
> For choices using
> [Django's TextChoices/IntegerChoices](https://docs.djangoproject.com/en/4.2/ref/models/fields/#enumeration-types)
> it is recommented using the [django-choices-field](../integrations/choices-field.md) integration
> enum handling.

## Relationships

All one-to-one, one-to-many, many-to-one and many-to-many relationship types are supported, and the many-to-many relation is described using the `typing.List` annotation.
The default resolver of `strawberry_django.fields()` resolves the relationship based on given type information.

```python title="types.py"
@strawberry_django.type(models.Fruit)
class Fruit:
    id: auto
    name: auto
    color: "Color"


@strawberry_django.type(models.Color)
class Color:
    id: auto
    name: auto
    fruits: list[Fruit]
```

Note that all relations can naturally trigger the n+1 problem. To avoid that, you can either
enable the [Optimizer Extension](./optimizer.md) which will automatically
solve some general issues for you, or even use
[Data Loaders](https://strawberry.rocks/docs/guides/dataloaders) for more complex
situations.

## Field customization

All Django types are encoded using the `strawberry_django.field()` field type by default. Fields can be customized with various parameters.

```python title="types.py"
@strawberry_django.type(models.Color)
class Color:
    another_name: auto = strawberry_django.field(field_name='name')
    internal_name: auto = strawberry_django.field(
        name='fruits',
        field_name='fruit_set',
        filters=FruitFilter,
        order=FruitOrder,
        pagination=True,
        description="A list of fruits with this color"
    )
```

## Defining types for auto fields

When using `strawberry.auto` to resolve a field's type, Strawberry Django uses a dict that maps
each django field field type to its proper type. e.g.:

```python
{
    models.CharField: str,
    models.IntegerField: int,
    ...,
}
```

If you are using a custom django field that is not part of the default library,
or you want to use a different type for a field, you can do that by overriding
its value in the map, like:

```python
from typing import NewType

from django.db import models
import strawberry
import strawberry_django
from strawberry_django.fields.types import field_type_map

Slug = strawberry.scalar(
    NewType("Slug", str),
    serialize=lambda v: v,
    parse_value=lambda v: v,
)

@strawberry_django.type
class MyCustomFileType:
    ...

field_type_map.update({
    models.SlugField: Slug,
    models.FileField: MyCustomFileType,
})
```

## Including / excluding Django model fields by name

> [!WARNING]
> These new keywords should be used with caution, as they may inadvertently lead to exposure of unwanted data. Especially with `fields="__all__"` or `exclude`, sensitive model attributes may be included and made available in the schema without your awareness.

`strawberry_django.type` includes two optional keyword fields to help you populate fields from the Django model, `fields` and `exclude`.

Valid values for `fields` are:

- `__all__` to assign `strawberry.auto` as the field type for all model fields.
- `[<List of field names>]` to assign `strawberry.auto` as the field type for the enumerated fields. These can be combined with manual type annotations if needed.

```python title="All Fields"
@strawberry_django.type(models.Fruit, fields="__all__")
class FruitType:
    pass
```

```python title="Enumerated Fields"
@strawberry_django.type(models.Fruit, fields=["name", "color"])
class FruitType:
    pass
```

```python title="Overriden Fields"
@strawberry_django.type(models.Fruit, fields=["color"])
class FruitType:
    name: str
```

Valid values for `exclude` are:

- `[<List of field names>]` to exclude from the fields list. All other Django model fields will included and have `strawberry.auto` as the field type. These can also be overriden if another field type should be assigned. An empty list is ignored.

```python title="Exclude Fields"
@strawberry_django.type(models.Fruit, exclude=["name"])
class FruitType:
    pass
```

```python title="Overriden Exclude Fields"
@strawberry_django.type(models.Fruit, exclude=["name"])
class FruitType:
    color: int
```

Note that `fields` has precedence over `exclude`, so if both are provided, then `exclude` is ignored.

## Overriding the field class (advanced)

If in your project, you want to change/add some of the standard `strawberry_django.field()` behaviour,
it is possible to use your own custom field class when decorating a `strawberry_django.type` with the `field_cls` argument, e.g.

```python title="types.py"
class CustomStrawberryDjangoField(StrawberryDjangoField):
    """Your custom behaviour goes here."""

@strawberry_django.type(User, field_cls=CustomStrawberryDjangoField)
class UserType:
    # Each of these fields will be an instance of `CustomStrawberryDjangoField`.
    id: int
    name: auto


@strawberry.type
class UserQuery:
    # You can directly create your custom field class on a plain strawberry type
    user: UserType = CustomStrawberryDjangoField()

```

In this example, each of the fields of the `UserType` will be automatically created by `CustomStrawberryDjangoField`,
which may implement anything from custom pagination of relationships to altering the field permissions.