Expressions Reference
This page documents query expressions for localized fields.
LocalizedRef
- class LocalizedRef(name, lang=None)
Query expression that selects a value in a specific language from a localized field.
Parameters:
name(str): The field/column namelang(str | None): Language code (uses active language if None)
Inherits From:
KeyTextTransform(Django’s JSON field transform)Usage:
Can be used in:
annotate()- Add computed fieldsvalues()- Select specific valuesorder_by()- Sort by localized contentfilter()- Filter by localized values (less common)update()- Update with computed values
Example:
from i18n_fields import LocalizedRef # Annotate with current language articles = Article.objects.annotate( title_text=LocalizedRef('title') ) # Annotate with specific language articles = Article.objects.annotate( title_en=LocalizedRef('title', 'en'), title_es=LocalizedRef('title', 'es') ) # Use in values() data = Article.objects.values( 'id', title=LocalizedRef('title', 'en') ) # Order by localized field articles = Article.objects.order_by(LocalizedRef('title'))
With Aggregations:
from django.db.models import Count # Count articles by first letter of English title from django.db.models.functions import Left stats = Article.objects.annotate( title_en=LocalizedRef('title', 'en'), first_letter=Left('title_en', 1) ).values('first_letter').annotate( count=Count('id') )
With Other Functions:
from django.db.models.functions import Upper, Length # Convert to uppercase articles = Article.objects.annotate( title_upper=Upper(LocalizedRef('title', 'en')) ) # Get length articles = Article.objects.annotate( title_length=Length(LocalizedRef('title', 'en')) )
L()
- L(name, lang=None)
Shorthand function for
LocalizedRef.Parameters:
name(str): The field/column namelang(str | None): Language code (uses active language if None)
Returns:
LocalizedRefinstanceExample:
from i18n_fields import L # Instead of LocalizedRef('title', 'en') articles = Article.objects.order_by(L('title', 'en')) # Current language articles = Article.objects.order_by(L('title')) # In values() data = Article.objects.values('id', title=L('title'))
Why Use L()?
Shorter and more readable
Commonly used in queries
Follows Django’s convention (like F() and Q())
Common Use Cases
Ordering
Order by localized fields in different languages:
from i18n_fields import L
# Order by current language
Article.objects.order_by(L('title'))
# Order by English title
Article.objects.order_by(L('title', 'en'))
# Descending order
Article.objects.order_by(L('title').desc())
# Multiple fields
Article.objects.order_by(L('category'), L('title'))
Annotations
Add computed fields based on localized content:
from i18n_fields import LocalizedRef
from django.db.models.functions import Upper, Concat
from django.db.models import Value, CharField
# Add uppercase title
articles = Article.objects.annotate(
title_upper=Upper(LocalizedRef('title', 'en'))
)
# Concatenate with string
articles = Article.objects.annotate(
full_title=Concat(
LocalizedRef('title', 'en'),
Value(' - Article'),
output_field=CharField()
)
)
# Multiple languages
articles = Article.objects.annotate(
title_en=LocalizedRef('title', 'en'),
title_es=LocalizedRef('title', 'es'),
title_fr=LocalizedRef('title', 'fr')
)
Values Queries
Extract specific language values:
from i18n_fields import L
# Get English titles
titles = Article.objects.values_list(L('title', 'en'), flat=True)
# Get multiple fields
data = Article.objects.values(
'id',
'created_at',
title=L('title', 'en'),
content=L('content', 'en')
)
# Multiple languages
data = Article.objects.values(
'id',
title_en=L('title', 'en'),
title_es=L('title', 'es')
)
Filtering
Filter by localized values (note: direct field lookups are usually better):
from i18n_fields import LocalizedRef
from django.db.models import Q
# Filter by annotation
articles = Article.objects.annotate(
title_en=LocalizedRef('title', 'en')
).filter(title_en='Hello World')
# Better: use direct lookup
articles = Article.objects.filter(title__en='Hello World')
Aggregations
Aggregate localized data:
from django.db.models import Count, Avg
from i18n_fields import LocalizedRef
# Count by category with English titles
stats = Article.objects.annotate(
title_en=LocalizedRef('title', 'en')
).values('category').annotate(
count=Count('id')
)
# Average rating by language
from django.db.models import Case, When, IntegerField
avg_rating = Article.objects.annotate(
rating_en=LocalizedRef('rating', 'en')
).aggregate(
avg=Avg('rating_en')
)
Advanced Examples
Conditional Expressions
Use with Case/When:
from django.db.models import Case, When, Value, CharField
from i18n_fields import LocalizedRef
# Choose title based on availability
articles = Article.objects.annotate(
display_title=Case(
When(
title__en__isnull=False,
then=LocalizedRef('title', 'en')
),
When(
title__es__isnull=False,
then=LocalizedRef('title', 'es')
),
default=Value('No title'),
output_field=CharField()
)
)
Subqueries
Use in subqueries:
from django.db.models import OuterRef, Subquery
from i18n_fields import LocalizedRef
# Get latest article title for each author
latest_articles = Article.objects.filter(
author=OuterRef('pk')
).order_by('-created_at')
authors = Author.objects.annotate(
latest_article_title=Subquery(
latest_articles.values(
title=LocalizedRef('title', 'en')
)[:1]
)
)
Window Functions
Use with window functions (PostgreSQL):
from django.db.models import F, Window
from django.db.models.functions import RowNumber
from i18n_fields import LocalizedRef
# Rank articles by title
articles = Article.objects.annotate(
title_en=LocalizedRef('title', 'en'),
rank=Window(
expression=RowNumber(),
order_by=F('title_en').asc()
)
)
Performance Considerations
Database Indexes
Consider adding indexes for frequently queried languages:
from django.contrib.postgres.indexes import GinIndex
class Article(models.Model):
title = LocalizedCharField(max_length=200)
class Meta:
indexes = [
# PostgreSQL GIN index
GinIndex(fields=['title']),
]
Query Optimization
from i18n_fields import L
# Good: Single annotation
articles = Article.objects.annotate(
title_en=L('title', 'en')
).order_by('title_en')
# Less efficient: Multiple queries
articles = Article.objects.all()
sorted_articles = sorted(articles, key=lambda a: a.title.get('en'))
Batch Operations
Use annotations for batch processing:
# Process in batches
articles = Article.objects.annotate(
title_en=L('title', 'en')
).values('id', 'title_en')
for batch in batch_qs(articles, batch_size=1000):
process_batch(batch)
Limitations
Database-Specific
Some features require specific databases:
GIN indexes: PostgreSQL only
Window functions: PostgreSQL, MySQL 8.0+
JSON Path Limitations
Complex JSON path queries may not work:
# May not work articles = Article.objects.filter( title__en__in=['Hello', 'World'] )
Type Conversions
Database returns string values for JSON fields. Type conversion happens in Python:
# Integer comparison may not work as expected products = Product.objects.annotate( stock_en=L('stock', 'en') ).filter(stock_en__gt=10) # May compare as strings
Best Practices
Use L() for Readability
Prefer
L()overLocalizedReffor brevity:# Good articles = Article.objects.order_by(L('title')) # More verbose from i18n_fields import LocalizedRef articles = Article.objects.order_by(LocalizedRef('title'))
Specify Language When Needed
Be explicit about language for consistent results:
# Good - explicit articles = Article.objects.order_by(L('title', 'en')) # May vary based on active language articles = Article.objects.order_by(L('title'))
Use Direct Lookups for Filtering
Prefer field lookups over expressions for filtering:
# Good articles = Article.objects.filter(title__en='Hello') # Less efficient articles = Article.objects.annotate( title_en=L('title', 'en') ).filter(title_en='Hello')
Combine with select_related
Optimize queries with related fields:
articles = Article.objects.select_related( 'author', 'category' ).annotate( title_en=L('title', 'en') ).order_by('title_en')
See Also
Advanced Queries - Advanced querying guide
Fields Reference - Localized field types