Registry / web-framework / django-parler

django-parler

JSON →
library2.4pypypiunverified

Django Parler (current version 2.3) provides simple Django model translations without nasty hacks, featuring nice admin integration. It enables storing multiple language versions of model fields in a separate table. The library is actively maintained with updates for Django compatibility and new features regularly released.

pip install django-parler
INSTALL
IMPORT
SIG · DJANGO-PARLER
D
django-parler
web-frameworkpythonv2.4
Install
3.5s avg
Import
Disk
66MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
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
musl
py 3.103.920 runs
installs and imports cleanly · install 0.0s · import 0.000s · 67.3MB
glibc
py 3.103.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.
fix
Manually 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.
fix
Ensure 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.
fix
To 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`).
fix
Use `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.
fix
As 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.

Agent activity
4 hits · last 30 days
node
4
Resources
django-parler — pip install django-parler · libregistry