Source code for translations.query

"""This module contains the query utilities for the Translations app."""

import copy

from django.db.models import Q
from django.db.models.constants import LOOKUP_SEP

from translations.languages import _get_default_language, _get_probe_language
from translations.utils import _get_dissected_lookup


__docformat__ = 'restructuredtext'


[docs]def _fetch_translations_query_getter(model, lang): """ Return the translations query getter specialized for a model and some language(s). """ default = _get_default_language() def _get_translations_query(*args, **kwargs): connector = kwargs.pop('_connector', None) negated = kwargs.pop('_negated', False) children = list(args) + sorted(kwargs.items()) for index, child in enumerate(children): if isinstance(child, tuple): dissected = _get_dissected_lookup(model, child[0]) if dissected['translatable']: query_default = False query_languages = None if isinstance(lang, (list, tuple)): query_languages = [] for x in lang: if x == default: query_default = True else: query_languages.append(x) else: if lang == default: query_default = True query_languages = None else: query_default = False query_languages = lang q = Q() if query_default: q |= Q(**{child[0]: child[1]}) if query_languages: relation = LOOKUP_SEP.join( dissected['relation'] + ['translations']) field_supp = (LOOKUP_SEP + dissected['supplement']) \ if dissected['supplement'] else '' lang_supp = (LOOKUP_SEP + 'in') \ if isinstance(query_languages, (list, tuple)) \ else '' q |= Q(**{ '{}__field'.format(relation): dissected['field'], '{}__text{}'.format(relation, field_supp): child[1], '{}__language{}'.format(relation, lang_supp): query_languages }) else: q = Q(**{child[0]: child[1]}) elif isinstance(child, TQ): if child.lang: getter = _fetch_translations_query_getter( model, child.lang ) q = getter( *child.children, _connector=child.connector, _negated=child.negated ) else: q = _get_translations_query( *child.children, _connector=child.connector, _negated=child.negated ) elif isinstance(child, Q): q = _get_translations_query( *child.children, _connector=child.connector, _negated=child.negated ) children[index] = q query = Q(*children, _connector=connector, _negated=negated) return query return _get_translations_query
[docs]class TQ(Q): """ Encapsulate translation queries as objects that can then be combined logically (using `&` and `|`). """
[docs] def __init__(self, *args, **kwargs): """Initialize a `TQ` with `Q` arguments.""" super(TQ, self).__init__(*args, **kwargs) self.lang = None
[docs] def __deepcopy__(self, memodict): """Return a copy of the `TQ` object.""" obj = super(TQ, self).__deepcopy__(memodict) obj.lang = self.lang return obj
[docs] def __call__(self, lang=None): """Specialize the `TQ` for some language(s).""" obj = copy.deepcopy(self) obj.lang = _get_probe_language(lang) return obj
[docs] def _combine(self, other, conn): """Return the result of logical combination with another `Q` object.""" if not isinstance(other, Q): raise TypeError(other) # If the other Q() is empty, ignore it and just use `self`. if not other: return copy.deepcopy(self) # Or if this Q is empty, ignore it and just use `other`. elif not self: return copy.deepcopy(other) obj = Q(self, other, _connector=conn) return obj