0
# Query Interface
1
2
Multilingual managers and querysets that automatically handle language-specific database queries, field lookups, and provide fallback functionality for missing translations.
3
4
## Capabilities
5
6
### Multilingual Manager
7
8
Custom manager that automatically rewrites queries to use appropriate translation fields based on the current language.
9
10
```python { .api }
11
class MultilingualManager(models.Manager):
12
"""
13
Manager for multilingual models that handles language-aware queries.
14
15
Automatically:
16
- Rewrites field lookups to use current language fields
17
- Handles fallback languages for queries
18
- Manages related model query rewriting
19
"""
20
21
def get_queryset(self):
22
"""Return queryset with translation field rewriting."""
23
24
def filter(self, *args, **kwargs):
25
"""Filter with automatic translation field rewriting."""
26
27
def exclude(self, *args, **kwargs):
28
"""Exclude with automatic translation field rewriting."""
29
30
def order_by(self, *field_names):
31
"""Order by with translation field rewriting."""
32
```
33
34
**Usage Example:**
35
36
```python
37
from modeltranslation.manager import MultilingualManager
38
39
class Article(models.Model):
40
title = models.CharField(max_length=255)
41
content = models.TextField()
42
43
objects = MultilingualManager()
44
45
# Queries automatically use current language
46
articles = Article.objects.filter(title__icontains='django')
47
# Becomes: filter(title_en__icontains='django') if current language is 'en'
48
49
articles = Article.objects.order_by('title')
50
# Becomes: order_by('title_en') if current language is 'en'
51
```
52
53
### Multilingual QuerySet
54
55
QuerySet that provides language-aware query operations and fallback handling.
56
57
```python { .api }
58
class MultilingualQuerySet(models.QuerySet):
59
"""
60
QuerySet with automatic translation field handling.
61
62
Features:
63
- Language-aware field lookups
64
- Fallback language support
65
- Translation field aggregation
66
"""
67
68
def filter(self, *args, **kwargs):
69
"""Filter with translation field rewriting."""
70
71
def exclude(self, *args, **kwargs):
72
"""Exclude with translation field rewriting."""
73
74
def order_by(self, *field_names):
75
"""Order with translation field rewriting."""
76
77
def values(self, *fields):
78
"""Values with translation and fallback field inclusion."""
79
80
def values_list(self, *fields, **kwargs):
81
"""Values list with translation field handling."""
82
```
83
84
### Combined Manager/QuerySet
85
86
Manager that provides both manager and queryset functionality in one class.
87
88
```python { .api }
89
class MultilingualQuerysetManager(MultilingualManager):
90
"""
91
Combined manager/queryset providing both manager and queryset methods.
92
Enables method chaining while maintaining translation functionality.
93
"""
94
95
def get_queryset(self):
96
"""Return MultilingualQuerySet instance."""
97
98
# Inherits all QuerySet methods for chaining
99
```
100
101
**Usage Example:**
102
103
```python
104
class Article(models.Model):
105
title = models.CharField(max_length=255)
106
content = models.TextField()
107
published = models.BooleanField(default=False)
108
109
objects = MultilingualQuerysetManager.from_queryset(MultilingualQuerySet)()
110
111
# Method chaining with translation support
112
recent_articles = (Article.objects
113
.filter(published=True)
114
.filter(title__icontains='django')
115
.order_by('-created_at')[:10])
116
```
117
118
### Field Lookup Rewriting
119
120
Automatic rewriting of field lookups to use appropriate translation fields.
121
122
```python { .api }
123
def rewrite_lookup_key(model, lookup_key):
124
"""
125
Rewrite field lookup keys to use translation fields.
126
127
Parameters:
128
- model: Model class being queried
129
- lookup_key: Original lookup key (e.g., 'title__icontains')
130
131
Returns:
132
- str: Rewritten lookup key (e.g., 'title_en__icontains')
133
"""
134
135
def get_translatable_fields_for_model(model):
136
"""
137
Get list of translatable field names for a model.
138
139
Parameters:
140
- model: Model class
141
142
Returns:
143
- list: Field names that are translatable, or None if not registered
144
"""
145
```
146
147
**Lookup Rewriting Examples:**
148
149
```python
150
# Simple field lookups
151
Article.objects.filter(title='Django')
152
# → filter(title_en='Django')
153
154
# Complex lookups with field transforms
155
Article.objects.filter(title__icontains='django', content__startswith='This')
156
# → filter(title_en__icontains='django', content_en__startswith='This')
157
158
# Related field lookups
159
Article.objects.filter(category__name='Technology')
160
# → filter(category__name_en='Technology') if Category.name is translatable
161
162
# Date/numeric fields work normally
163
Article.objects.filter(created_at__gte=date.today())
164
# → No rewriting needed for non-translatable fields
165
```
166
167
### Fallback Field Handling
168
169
Automatic inclusion of fallback language fields in queries and values.
170
171
```python { .api }
172
def append_fallback(model, fields):
173
"""
174
Add fallback language fields to field list.
175
176
Parameters:
177
- model: Model class
178
- fields: Sequence of field names
179
180
Returns:
181
- tuple: (expanded_fields_set, translated_field_names_set)
182
"""
183
184
def append_translated(model, fields):
185
"""
186
Add all translation fields for given field names.
187
188
Parameters:
189
- model: Model class
190
- fields: Iterable of field names
191
192
Returns:
193
- set: All translation field names for given fields
194
"""
195
```
196
197
**Fallback Usage:**
198
199
```python
200
# When querying values, fallback fields are automatically included
201
articles = Article.objects.values('title', 'content')
202
203
# If current language is 'fr' with fallback to 'en', this becomes:
204
# values('title_fr', 'title_en', 'content_fr', 'content_en')
205
206
# The model instance will show the French value if available,
207
# otherwise the English fallback
208
```
209
210
### Language-Aware Aggregation
211
212
Aggregation functions that work with translation fields and fallbacks.
213
214
```python
215
from django.db.models import Count, Q
216
from modeltranslation.utils import get_language
217
218
# Count articles with non-empty titles in current language
219
current_lang = get_language()
220
Article.objects.aggregate(
221
count=Count('id', filter=Q(**{f'title_{current_lang}__isnull': False}))
222
)
223
224
# Aggregate across all languages
225
from modeltranslation.settings import AVAILABLE_LANGUAGES
226
227
for lang in AVAILABLE_LANGUAGES:
228
count = Article.objects.filter(**{f'title_{lang}__isnull': False}).count()
229
print(f"Articles with {lang} title: {count}")
230
```
231
232
### Custom QuerySet Methods
233
234
Extend querysets with translation-specific methods.
235
236
```python
237
class ArticleQuerySet(MultilingualQuerySet):
238
def published(self):
239
"""Filter for published articles."""
240
return self.filter(published=True)
241
242
def with_translation(self, language=None):
243
"""Filter articles that have translation in specified language."""
244
from modeltranslation.utils import get_language
245
lang = language or get_language()
246
247
# Get translatable fields for this model
248
from modeltranslation.translator import translator
249
opts = translator.get_options_for_model(self.model)
250
251
# Create filter conditions for non-empty translation fields
252
conditions = Q()
253
for field_name in opts.fields:
254
field_lookup = f"{field_name}_{lang}__isnull"
255
conditions &= ~Q(**{field_lookup: True})
256
257
return self.filter(conditions)
258
259
def missing_translation(self, language=None):
260
"""Filter articles missing translation in specified language."""
261
from modeltranslation.utils import get_language
262
lang = language or get_language()
263
264
from modeltranslation.translator import translator
265
opts = translator.get_options_for_model(self.model)
266
267
conditions = Q()
268
for field_name in opts.fields:
269
field_lookup = f"{field_name}_{lang}__isnull"
270
conditions |= Q(**{field_lookup: True})
271
272
return self.filter(conditions)
273
274
class Article(models.Model):
275
title = models.CharField(max_length=255)
276
content = models.TextField()
277
published = models.BooleanField(default=False)
278
279
objects = MultilingualQuerysetManager.from_queryset(ArticleQuerySet)()
280
281
# Usage
282
published_with_french = Article.objects.published().with_translation('fr')
283
missing_german = Article.objects.missing_translation('de')
284
```
285
286
### Related Model Queries
287
288
Handle translation fields in related model queries and joins.
289
290
```python
291
# Related model lookups are automatically rewritten
292
Article.objects.filter(category__name='Technology')
293
# If Category.name is translatable:
294
# → filter(category__name_en='Technology')
295
296
# Prefetch related with translations
297
Article.objects.prefetch_related('category').filter(title__icontains='django')
298
299
# Select related with translation fields
300
Article.objects.select_related('category').values('title', 'category__name')
301
# Automatically includes appropriate translation fields
302
```
303
304
## Advanced Usage
305
306
### Custom Field Resolution
307
308
Override field resolution for complex translation scenarios.
309
310
```python
311
class CustomMultilingualQuerySet(MultilingualQuerySet):
312
def _rewrite_filter_args(self, *args, **kwargs):
313
"""Custom logic for rewriting filter arguments."""
314
# Custom field resolution logic
315
return super()._rewrite_filter_args(*args, **kwargs)
316
```
317
318
### Performance Optimization
319
320
Optimize queries for large datasets with translations.
321
322
```python
323
# Use only() and defer() with translation fields
324
Article.objects.only('title_en', 'title_fr').filter(published=True)
325
326
# Defer translation fields not needed immediately
327
Article.objects.defer('content_de', 'content_es').filter(category__name='Tech')
328
329
# Use select_related for foreign key translations
330
Article.objects.select_related('category').filter(title__icontains='django')
331
```
332
333
### Raw SQL with Translations
334
335
Handle raw SQL queries with translation field names.
336
337
```python
338
from modeltranslation.utils import build_localized_fieldname, get_language
339
340
current_lang = get_language()
341
title_field = build_localized_fieldname('title', current_lang)
342
343
# Raw query with dynamic field names
344
Article.objects.extra(
345
where=[f"{title_field} ILIKE %s"],
346
params=['%django%']
347
)
348
```
349
350
### Bulk Operations
351
352
Bulk create, update, and delete operations with translation fields.
353
354
```python
355
# Bulk create with translation fields
356
articles = [
357
Article(title_en='English Title', title_fr='Titre Français'),
358
Article(title_en='Another Title', title_fr='Autre Titre'),
359
]
360
Article.objects.bulk_create(articles)
361
362
# Bulk update translation fields
363
Article.objects.filter(category_id=1).update(
364
title_fr='Nouveau Titre',
365
content_fr='Nouveau contenu'
366
)
367
```