Skip to content

Commit a19e884

Browse files
committed
Move hvad settings to HVAD dict, and add settings for basic customizable behaviors.
1 parent 1e52b43 commit a19e884

File tree

11 files changed

+213
-83
lines changed

11 files changed

+213
-83
lines changed

docs/public/release_notes.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,27 @@ Python and Django versions supported:
1212
- So, as a reminder, supported Django versions for this release are:
1313
1.8 LTS, 1.9, 1.10.x (for x ≥ 1).
1414

15+
New features:
16+
17+
- Automatic loading of translations on attribute access can now be disabled,
18+
by setting ``HVAD["AUTOLOAD_TRANSLATIONS"]`` to ``False``. This will prevent
19+
hvad from initiating database queries. Accessing translatable attributes with
20+
no translation loaded will then raise an :exc:`~exceptions.AttributeError`.
21+
- It is possible to automatically install :class:`~hvad.manager.TranslationQueryset`
22+
as the default queryset for all translatable models, by setting
23+
``HVAD["USE_DEFAULT_QUERYSET"]`` to ``True``. Specifically, it changes
24+
:attr:`~hvad.manager.TranslationManager.default_class` to be a
25+
:class:`~hvad.manager.TranslationQueryset` instead of a
26+
:class:`~django.db.models.query.QuerySet`.
27+
See the section about
28+
:ref:`overriding the default queryset <override-default-queryset>`
29+
for advantages and caveats of doing so.
30+
1531
Compatibility warnings:
1632

33+
- All settings have been moved to a unique ``HVAD`` dictionary. Please update
34+
your django settings accordingly.
35+
1736
- Deprecated class :class:`~ hvad.manager.FallbackQueryset` has been removed.
1837
Using it along with
1938
:meth:`FallbackQueryset.use_fallbacks() <hvad.manager.FallbackQueryset.use_fallbacks>`

hvad/admin.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import functools
2-
import django
32
import warnings
4-
from django.conf import settings
53
from django.contrib.admin.options import ModelAdmin, csrf_protect_m, InlineModelAdmin
64
from django.contrib.admin.utils import flatten_fieldsets, unquote, get_deleted_objects
75
from django.contrib.contenttypes.models import ContentType
@@ -16,14 +14,13 @@
1614
from django.template.loader import select_template
1715
from django.utils.encoding import iri_to_uri, force_text
1816
from django.utils.functional import curry
19-
from django.utils.translation import ugettext_lazy as _, get_language
17+
from django.utils.translation import ugettext_lazy as _, get_language, get_language_info
2018
from hvad.compat import urlencode, urlparse
2119
from hvad.forms import TranslatableModelForm, translatable_inlineformset_factory, translatable_modelform_factory
20+
from hvad.settings import hvad_settings
2221
from hvad.utils import load_translation
23-
from hvad.manager import FALLBACK_LANGUAGES, TranslationQueryset
22+
from hvad.manager import TranslationQueryset
2423

25-
def get_language_name(language_code):
26-
return dict(settings.LANGUAGES).get(language_code, language_code)
2724

2825
class InlineModelForm(TranslatableModelForm):
2926
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
@@ -84,7 +81,7 @@ def get_language_tabs(self, obj, request, available_languages):
8481
tabs = []
8582
get = request.GET.copy()
8683
language = self._language(request)
87-
for key, name in settings.LANGUAGES:
84+
for key, name in hvad_settings.LANGUAGES:
8885
get['language'] = key
8986
url = '%s?%s' % (request.path, get.urlencode())
9087
if language == key:
@@ -163,7 +160,7 @@ def get_form(self, request, obj=None, **kwargs):
163160
def render_change_form(self, request, context, add=False, change=False,
164161
form_url='', obj=None):
165162
lang_code = self._language(request)
166-
lang = get_language_name(lang_code)
163+
lang = get_language_info(lang_code)['name_local']
167164
available_languages = self.get_available_languages(obj)
168165

169166
context.update({
@@ -229,8 +226,7 @@ def delete_translation(self, request, object_id, language_code):
229226
deleted_objects, model_count, perms_needed, protected = get_deleted_objects(
230227
[obj], translations_model._meta, request.user, self.admin_site, using)
231228

232-
lang = get_language_name(language_code)
233-
229+
lang = get_language_info(language_code)['name_local']
234230

235231
if request.POST: # The user has already confirmed the deletion.
236232
if perms_needed:
@@ -285,7 +281,7 @@ def deletion_not_allowed(self, request, obj, language_code):
285281
'language_code': language_code,
286282
'opts': opts,
287283
'app_label': opts.app_label,
288-
'language_name': get_language_name(language_code),
284+
'language_name': get_language_info(language_code)['name_local'],
289285
'object_name': force_text(opts.verbose_name),
290286
},
291287
)
@@ -328,7 +324,7 @@ def get_object(self, request, object_id, from_field=None):
328324

329325
def get_queryset(self, request):
330326
language = self._language(request)
331-
qs = self.model._default_manager.language(language).fallbacks(*FALLBACK_LANGUAGES)
327+
qs = self.model._default_manager.language(language).fallbacks(*hvad_settings.FALLBACK_LANGUAGES)
332328

333329
# TODO: this should be handled by some parameter to the ChangeList.
334330
ordering = getattr(self, 'ordering', None) or ()

hvad/descriptors.py

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,46 @@
1-
from django.utils.translation import get_language
2-
from hvad.utils import get_translation, set_cached_translation, get_cached_translation
31
from django.apps import registry
2+
from django.utils.translation import get_language
3+
from hvad.settings import hvad_settings
4+
from hvad.utils import get_translation, set_cached_translation
45

5-
6-
class BaseDescriptor(object):
7-
"""
8-
Base descriptor class with a helper to get the translations instance.
6+
class TranslatedAttribute(object):
7+
""" Proxy descriptor, forwarding attribute access to loaded translation.
8+
If no translation is loaded, it will attempt to load one depending on settings
99
"""
10-
def __init__(self, opts):
11-
self.opts = opts
10+
11+
def __init__(self, model, name):
12+
self.translations_model = model._meta.translations_model
13+
self.name = name
1214
self._NoTranslationError = type('NoTranslationError',
13-
(AttributeError, opts.translations_model.DoesNotExist),
15+
(AttributeError, model._meta.translations_model.DoesNotExist),
1416
{})
15-
17+
super(TranslatedAttribute, self).__init__()
18+
1619
def translation(self, instance):
17-
translation = get_cached_translation(instance)
18-
if translation is None:
20+
try:
21+
return getattr(instance, instance._meta.translations_cache)
22+
except AttributeError:
23+
pass
24+
25+
if hvad_settings.AUTOLOAD_TRANSLATIONS:
1926
try:
2027
translation = get_translation(instance)
21-
except self.opts.translations_model.DoesNotExist:
28+
except instance._meta.translations_model.DoesNotExist:
2229
raise self._NoTranslationError('Accessing a translated field requires that '
2330
'the instance has a translation loaded, or a '
2431
'valid translation in current language (%s) '
2532
'loadable from the database' % get_language())
2633
set_cached_translation(instance, translation)
27-
return translation
28-
29-
30-
class TranslatedAttribute(BaseDescriptor):
31-
""" Proxies attributes from the shared instance to the translated instance. """
32-
33-
def __init__(self, opts, name):
34-
self.name = name
35-
super(TranslatedAttribute, self).__init__(opts)
34+
return translation
35+
else:
36+
raise AttributeError('No translation loaded and auto-loading is disabled because '
37+
'settings.HVAD[\'AUTOLOAD_TRANSLATIONS\'] is False')
3638

3739
def __get__(self, instance, instance_type=None):
3840
if not instance:
3941
if not registry.apps.ready: #pragma: no cover
4042
raise AttributeError('Attribute not available until registry is ready.')
41-
return self.opts.translations_model._meta.get_field(self.name).default
43+
return self.translations_model._meta.get_field(self.name).default
4244
return getattr(self.translation(instance), self.name)
4345

4446
def __set__(self, instance, value):
@@ -54,8 +56,8 @@ class LanguageCodeAttribute(TranslatedAttribute):
5456
be deleted. Trying to do so will always cause an attribute error.
5557
5658
"""
57-
def __init__(self, opts):
58-
super(LanguageCodeAttribute, self).__init__(opts, 'language_code')
59+
def __init__(self, model):
60+
super(LanguageCodeAttribute, self).__init__(model, 'language_code')
5961

6062
def __set__(self, instance, value):
6163
raise AttributeError("The 'language_code' attribute cannot be changed directly.")

hvad/forms.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
from django.conf import settings
21
from django.core.exceptions import FieldError, ValidationError
32
from django.forms.fields import CharField
43
from django.forms.formsets import formset_factory
@@ -10,6 +9,7 @@
109
from django.utils.translation import get_language, ugettext as _
1110
from hvad.compat import with_metaclass
1211
from hvad.models import TranslatableModel, BaseTranslationModel
12+
from hvad.settings import hvad_settings
1313
from hvad.utils import (set_cached_translation, get_cached_translation, load_translation)
1414
from collections import OrderedDict
1515

@@ -326,7 +326,7 @@ def add_fields(self, form, index):
326326
if not 'language_code' in form.fields:
327327
form.fields['language_code'] = CharField(
328328
required=True, initial=form.instance.language_code,
329-
widget=Select(choices=(('', '--'),)+settings.LANGUAGES)
329+
widget=Select(choices=(('', '--'),)+hvad_settings.LANGUAGES)
330330
)
331331
# Add language_code to self._meta.fields so it is included in validation stage
332332
try:

hvad/manager.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import django
2-
from django.conf import settings
32
from django.core.exceptions import FieldError
43
from django.db import connections, models, transaction, IntegrityError
54
if django.VERSION >= (1, 9):
@@ -13,7 +12,8 @@
1312
from hvad.compat import string_types
1413
from hvad.query import (query_terms, q_children, expression_nodes,
1514
add_alias_constraints)
16-
from hvad.utils import combine, settings_updater
15+
from hvad.settings import hvad_settings
16+
from hvad.utils import combine
1717
from copy import deepcopy
1818
import logging
1919
import sys
@@ -23,12 +23,6 @@
2323
# Logging-related globals
2424
_logger = logging.getLogger(__name__)
2525

26-
# Global settings, wrapped so they react to SettingsOverride
27-
@settings_updater
28-
def update_settings(*args, **kwargs):
29-
global FALLBACK_LANGUAGES
30-
FALLBACK_LANGUAGES = tuple(code for code, name in settings.LANGUAGES)
31-
3226
#===============================================================================
3327

3428
class FieldTranslator(object):
@@ -463,7 +457,7 @@ def language(self, language_code=None):
463457

464458
def fallbacks(self, *fallbacks):
465459
if not fallbacks:
466-
self._language_fallbacks = FALLBACK_LANGUAGES
460+
self._language_fallbacks = hvad_settings.FALLBACK_LANGUAGES
467461
elif fallbacks == (None,):
468462
self._language_fallbacks = None
469463
else:
@@ -779,7 +773,7 @@ class TranslationManager(models.Manager):
779773

780774
queryset_class = TranslationQueryset
781775
fallback_class = QuerySet
782-
default_class = QuerySet
776+
default_class = TranslationQueryset if hvad_settings.USE_DEFAULT_QUERYSET else QuerySet
783777

784778
def __init__(self, *args, **kwargs):
785779
self.queryset_class = kwargs.pop('queryset_class', self.queryset_class)

hvad/models.py

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import django
22
from django.core import checks
33
from django.core.exceptions import ImproperlyConfigured
4-
from django.conf import settings
54
from django.db import models
65
from django.db.models.base import ModelBase
76
from django.db.models.fields import FieldDoesNotExist
@@ -10,23 +9,15 @@
109
from django.utils.translation import get_language
1110
from hvad.descriptors import LanguageCodeAttribute, TranslatedAttribute
1211
from hvad.manager import TranslationManager, TranslationsModelManager
12+
from hvad.settings import hvad_settings
1313
from hvad.utils import (get_cached_translation, set_cached_translation,
14-
SmartGetFieldByName, SmartGetField, settings_updater)
14+
SmartGetFieldByName, SmartGetField)
1515
from hvad.compat import MethodType
1616
from itertools import chain
1717
import sys
1818

1919
#===============================================================================
2020

21-
# Global settings, wrapped so they react to SettingsOverride
22-
@settings_updater
23-
def update_settings(*args, **kwargs):
24-
global FALLBACK_LANGUAGES, TABLE_NAME_SEPARATOR
25-
FALLBACK_LANGUAGES = tuple( code for code, name in settings.LANGUAGES )
26-
TABLE_NAME_SEPARATOR = getattr(settings, 'HVAD_TABLE_NAME_SEPARATOR', '_')
27-
28-
#===============================================================================
29-
3021
class TranslatedFields(object):
3122
""" Wrapper class to define translated fields on a model. """
3223

@@ -146,7 +137,7 @@ def _build_meta_class(self, model, tfields):
146137
'managed': model._meta.managed,
147138
'app_label': model._meta.app_label,
148139
'db_table': meta.get('db_table',
149-
'%s%stranslation' % (model._meta.db_table, TABLE_NAME_SEPARATOR)),
140+
hvad_settings.TABLE_NAME_FORMAT % (model._meta.db_table,)),
150141
'default_permissions': (),
151142
})
152143

@@ -182,12 +173,12 @@ def contribute_translations(self, model, translations_model, related_name):
182173
if field.name in ignore_fields:
183174
continue
184175
if field.name == 'language_code':
185-
attr = LanguageCodeAttribute(model._meta)
176+
attr = LanguageCodeAttribute(model)
186177
else:
187-
attr = TranslatedAttribute(model._meta, field.name)
178+
attr = TranslatedAttribute(model, field.name)
188179
attname = field.get_attname()
189180
if attname and attname != field.name:
190-
setattr(model, attname, TranslatedAttribute(model._meta, attname))
181+
setattr(model, attname, TranslatedAttribute(model, attname))
191182
setattr(model, field.name, attr)
192183

193184
#===============================================================================
@@ -238,8 +229,6 @@ def __init__(self, *args, **kwargs):
238229
else:
239230
tkwargs[key] = value
240231
super(TranslatableModel, self).__init__(*args, **skwargs)
241-
242-
# Create a translation if there are translated fields
243232
if tkwargs:
244233
tkwargs['language_code'] = tkwargs.get('language_code') or get_language()
245234
set_cached_translation(self, self._meta.translations_model(**tkwargs))
@@ -313,7 +302,7 @@ def lazy_translation_getter(self, name, default=None):
313302
translation_dict = dict((t.language_code, t) for t in translations)
314303

315304
# see if we have the right language, or any language in fallbacks
316-
for code in (get_language(), settings.LANGUAGE_CODE) + FALLBACK_LANGUAGES:
305+
for code in (get_language(),) + hvad_settings.FALLBACK_LANGUAGES:
317306
try:
318307
translation = translation_dict[code]
319308
except KeyError:

0 commit comments

Comments
 (0)