Install & Compatibility
Where this runs
tested against v2.4 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.920 runs
installs and imports cleanly · install 0.0s · import 0.000s · 67.3MB
glibcpy 3.10–3.920 runs
installs and imports cleanly · install 3.5s · import 0.000s · 68MB
66MB installed
● package 66MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
TranslatableModel
✓ from parler.models import TranslatableModel
✗ from parler.models import TranslatableModel
To quickly get started with django-parler, first install it and add `'parler'` to your `INSTALLED_APPS`. Configure `LANGUAGES` and `PARLER_LANGUAGES` in `settings.py`. Define your models by inheriting from `TranslatableModel` and wrapping translatable fields in `TranslatedFields`. Register your model with `TranslatableAdmin` in `admin.py` for full administrative support. Access translations using `set_current_language()` or `django.utils.translation.override()` and query with `.translated()` or `.active_translations()` methods.
# settings.py
INSTALLED_APPS = [
# ...
'parler',
# Your app
'myapp',
]
LANGUAGE_CODE = 'en'
LANGUAGES = (
('en', 'English'),
('fr', 'French'),
('es', 'Spanish'),
)
PARLER_LANGUAGES = {
None: (
{'code': 'en'},
{'code': 'fr'},
{'code': 'es'},
),
'default': {
'fallbacks': ['en'],
'hide_untranslated': False,
}
}
# myapp/models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
from parler.models import TranslatableModel, TranslatedFields
class Category(TranslatableModel):
translations = TranslatedFields(
name=models.CharField(_("Name"), max_length=200, unique=True)
)
# Add a non-translatable field for demonstration
is_active = models.BooleanField(default=True)
def __str__(self):
return self.safe_translation_getter('name', any_language=True)
# myapp/admin.py
from django.contrib import admin
from parler.admin import TranslatableAdmin
from .models import Category
@admin.register(Category)
class CategoryAdmin(TranslatableAdmin):
list_display = ('name', 'is_active',)
# Prepopulated fields (if you had a slug for example)
# prepopulated_fields = {'slug': ('name',)}
# Example usage in a shell or view
from django.utils import translation
# Create a category
cat = Category(is_active=True)
cat.set_current_language('en')
cat.name = "Electronics"
cat.save()
cat.set_current_language('fr')
cat.name = "Électronique"
cat.save()
# Accessing translations
with translation.override('en'):
print(f"English Name: {cat.name}") # Output: English Name: Electronics
with translation.override('fr'):
print(f"French Name: {cat.name}") # Output: French Name: Électronique
# Querying translated fields
# All categories with name 'Electronics' in any language
electronics_en = Category.objects.translated(name='Electronics').first()
print(f"Found in EN: {electronics_en.name}")
# Categories with active translations for current language or fallbacks
active_cats = Category.objects.active_translations().filter(is_active=True)
for c in active_cats:
print(f"Active Category ({c.get_current_language()}): {c.name}")
Debug
Known issues
breakingWhen migrating existing models to be translatable, directly running `makemigrations` and `migrate` can lead to various `TypeError`, `AttributeError`, or `DataError` exceptions. This is because `django-parler` stores translations in a separate table, and the ORM struggles with data migration for this change.fixManually create migration files. The process involves three distinct steps in order: 1. `CreateModel` for the new translation tables (manually adjust `bases` argument). 2. `RunSQL` operations to copy data from old fields to the new translation fields. 3. `RemoveField` to delete the original columns from the main model. Refer to the official 'Making existing fields translatable' guide.
affects: All versions, especially when upgrading existing models.
gotchaQuerying translatable fields (e.g., using `.translated()` or `.active_translations()`) cannot be chained with multiple `.filter()` calls for translatable fields due to ORM restrictions. Doing so might lead to incorrect or incomplete results. Also, `.active_translations()` often returns duplicate objects if `distinct()` is not used.fixEnsure all filters for translatable fields are applied within a single `.translated()` or `.active_translations()` call. For `.active_translations()`, always append `.distinct()` to avoid duplicates, e.g., `MyModel.objects.active_translations(title='Cheese').distinct()`.
affects: All versions
gotchaEnforcing unique constraints on translated fields (e.g., a unique product `slug` across all languages) requires explicit configuration. Simply adding `unique=True` to `CharField` inside `TranslatedFields` will enforce uniqueness across *all* translations, not per language.fixTo make a translated field unique per language, add `meta={'unique_together': [('language_code', 'field_name')]}` to the `TranslatedFields` declaration. Example: `translations = TranslatedFields(title=models.CharField(..., unique=False), meta={'unique_together': [('language_code', 'title')]})`. affects: All versions
gotchaAccessing a translated field when a translation is missing for the current language, and no fallbacks are defined or available, will raise a `TranslationDoesNotExist` exception (which inherits from `AttributeError`).fixUse `obj.safe_translation_getter('field_name', any_language=True)` to safely retrieve a translated value, which will return `None` or an empty string if no translation exists. Alternatively, declare the `TranslatedField` with `any_language=True` at the model level for automatic fallback to any available language. Configure robust `PARLER_LANGUAGES` fallbacks in `settings.py`. affects: All versions
breakingThere are reports of the admin JavaScript (parler.js) missing in version 2.3, which can break the functionality of `TranslatableAdmin` and prevent the display of language tabs in the Django admin interface.fixAs this appears to be a bug in specific releases, check the `django-parler` GitHub issues for patches or workarounds. Downgrading to a stable 2.x version or upgrading to a newer patch release (if available) might resolve it.
affects: 2.3 (and potentially other minor versions)
Upgrade
Version history
2.4latest on PyPI · released May 14, 2026
Audit
Dependencies
No dependency data recorded yet.