KristianOellegaard/django-hvad — pull request #184 by spectras (2014-05-26 16:28:28+00:00)
Title: Implement TranslationQueryset.fallbacks for Django 1.6+.

Django 1.6 added a new `get_extra_restriction()` callback to fields, making it possible to inject custom predicates in JOIN clauses. This feature was leveraged in 45e397341d6dacfc1c19c7d342816ece335bac8b to cut down query number from `N/100` to `1` and fetched row count from `N*F` to `N` (with `F` the number of fallback languages).

This PR uses this further, by introducing a `fallbacks()` method on `TranslationQueryset` on Django 1.6 and newer. This allows getting fallbacks the same way `FallbackQueryset` does, while retaining all the features of `TranslationQueryset` yet not compromising on performance (actually improving it in fact).

The intent is to fully replace all the `FallbackQueryset` stuff, with its `untranslated()`-accessor-that-returns-a-queryset-that-actually-translates-objects though, while translation-aware, cannot filter on translated fields.
Of course, as this requires Django 1.6 or newer, we will not actually remove `FallbackQueryset` anytime soon. Still, giving the option to do so to users of Django 1.6+ is good I think.

```pycon
>>> Book.objects.language('fr').fallbacks('en').filter(category=novels)
[, , ]
>>> Book.objects.language('ja').fallbacks('en').filter(category=novels)
[, , ]
>>> Book.objects.language('ja').fallbacks('fr', 'en').filter(category=novels)
[, , ]
```
__Allows the following forms:__
- `qs.fallbacks()`: use `settings.LANGUAGES` as fallback languages.
- `qs.fallbacks(None)`: disables fallbacks.
- `qs.fallbacks('en', 'ru', 'ja')`: sets the fallback list. Fallbacks priority is from first to last. `None` will be replaced with current language. Duplicate values are allowed (first wins).

Slight difference with `FallbackQueryset`: if an object has no translation available in one of the fallbacks languages, yet does have a translation available, an arbitrary translation will be picked. This is consistent with the behavior of `lazy_translation_getter`.