Skip to content

Commit

Permalink
added translation model mixin
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobias Lorenz committed Jan 15, 2015
1 parent 994c888 commit a15f2a5
Show file tree
Hide file tree
Showing 14 changed files with 170 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.txt
@@ -1,5 +1,6 @@
=== 1.65.X ===

- added hvad model mixin
- updated hvad factory mixin
- added get_site template tag
- added domain variable to email context
Expand Down
1 change: 1 addition & 0 deletions README.rst
Expand Up @@ -43,6 +43,7 @@ and applications.
* Function to convert html code into formatted plain text.
* Amazon S3 storage + django-compressor support files.
* An AJAX View to display paginated comments for every possible object.
* Tools to improve django-hvad

**Coming soon**:

Expand Down
64 changes: 59 additions & 5 deletions django_libs/models_mixins.py
@@ -1,12 +1,10 @@
"""Useful mixins for models."""
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.utils.translation import get_language

try:
from hvad.models import TranslationManager
except ImportError:
class TranslationManager(object):
pass
from hvad.models import NoTranslation, TranslationManager
from simple_translation.utils import get_preferred_translation_from_lang


Expand All @@ -29,6 +27,62 @@ def published(self, request, check_language=True):
return self.get_query_set().filter(**kwargs)


class TranslationModelMixin(object):
"""Mixin to provide custom django-hvad overrides."""
def __unicode__(self):
return self.translation_getter('title')

def check_for_result(self, language, translation, result, name):
if not result:
try:
translation = self.translations.get(language_code=language)
except ObjectDoesNotExist:
pass
else: # pragma: nocover
result = getattr(translation, name, '')
return translation, result

def translation_getter(self, name):
"""
Custom translation getter.
1. Try the current language
2. Try base language (e.g. 'en' instead of 'en-gb')
3. Try default sys language
4. Use any translation
"""
stuff = self.safe_translation_getter(name, NoTranslation)
if stuff is not NoTranslation:
return stuff

translation = None
result = None

# Check for the current language
translation, result = self.check_for_result(
get_language(), translation, result, name)

# Check for the current main language
translation, result = self.check_for_result(
get_language()[:2], translation, result, name)

# Check for the default language
translation, result = self.check_for_result(
settings.LANGUAGE_CODE, translation, result, name)

if not result:
# Check for any available language
for trans in self.translations.all(): # pragma: nocover
translation = trans
result = getattr(translation, name, '')
if result:
break

setattr(self, self._meta.translations_cache, translation)
return result


class SimpleTranslationMixin(object):
"""Adds a ``get_translation`` method to the model."""
def get_translation(self, language=None):
Expand Down
40 changes: 22 additions & 18 deletions django_libs/tests/factories.py
Expand Up @@ -16,7 +16,6 @@
from django.core.files.uploadedfile import SimpleUploadedFile
from django.utils.timezone import now

from mailer.models import MessageLog
from PIL import Image
from hashlib import md5
import factory
Expand Down Expand Up @@ -143,23 +142,6 @@ def _prepare(cls, create, **kwargs):
return user


class MessageLogFactory(factory.DjangoModelFactory):
"""
Creates a new ``MessageLog`` object.
We only use this factory for testing purposes (management command:
"cleanup_mailer_messagelog").
"""
FACTORY_FOR = MessageLog

message_data = 'foo'
when_added = factory.Sequence(lambda n: now())
priority = '3'
result = '1'
log_message = 'foo'


class SiteFactory(factory.DjangoModelFactory):
"""
Creates a new ``Site`` object.
Expand All @@ -169,3 +151,25 @@ class SiteFactory(factory.DjangoModelFactory):

name = factory.Sequence(lambda n: 'Example {}'.format(n))
domain = factory.Sequence(lambda n: 'example{}.com'.format(n))


try:
from mailer.models import MessageLog
except ImportError: # mailer not installed
pass
else:
class MessageLogFactory(factory.DjangoModelFactory):
"""
Creates a new ``MessageLog`` object.
We only use this factory for testing purposes (management command:
"cleanup_mailer_messagelog").
"""
FACTORY_FOR = MessageLog

message_data = 'foo'
when_added = factory.Sequence(lambda n: now())
priority = '3'
result = '1'
log_message = 'foo'
25 changes: 23 additions & 2 deletions django_libs/tests/model_mixins_tests.py
Expand Up @@ -2,9 +2,30 @@
from mock import Mock

from django.test import TestCase
from django.utils.translation import activate

from .test_app.factories import DummyProfileTranslationFactory
from .test_app.models import DummyProfile
from .test_app.factories import (
DummyProfileTranslationFactory,
HvadDummyFactory,
)
from .test_app.models import DummyProfile, HvadDummy


class TranslationModelMixinTestCase(TestCase):
"""Tests for the ``TranslationModelMixin`` model mixin."""
longMessage = True

def test_functions(self):
translated_obj = HvadDummyFactory()
self.assertEqual(translated_obj.translation_getter('title'), 'title1')
untranslated_obj = HvadDummy()
self.assertIsNone(untranslated_obj.translation_getter('title'))
untranslated_obj.translate('de')
untranslated_obj.title = 'foo'
untranslated_obj.save()
activate('de')
self.assertEqual(untranslated_obj.translation_getter('title'), 'foo')
activate('en')


class SimpleTranslationMixinTestCase(TestCase):
Expand Down
11 changes: 9 additions & 2 deletions django_libs/tests/test_app/factories.py
@@ -1,8 +1,15 @@
"""Just some factories for the test app."""
import factory

from ..factories import UserFactory
from models import DummyProfile, DummyProfileTranslation
from ..factories import HvadFactoryMixin, UserFactory
from models import DummyProfile, DummyProfileTranslation, HvadDummy


class HvadDummyFactory(HvadFactoryMixin, factory.DjangoModelFactory):
"""Factory for the ``HvadDummy`` model."""
FACTORY_FOR = HvadDummy

title = factory.Sequence(lambda n: 'title{}'.format(n))


class DummyProfileFactory(factory.DjangoModelFactory):
Expand Down
12 changes: 12 additions & 0 deletions django_libs/tests/test_app/models.py
Expand Up @@ -2,14 +2,26 @@
from django.db import models
from django.utils.translation import ugettext_lazy as _

from hvad.models import TranslatableModel, TranslatedFields
from simple_translation.translation_pool import translation_pool

from ...models_mixins import (
TranslationModelMixin,
SimpleTranslationMixin,
SimpleTranslationPublishedManager,
)


class HvadDummy(TranslationModelMixin, TranslatableModel):
"""Dummy model to test hvad stuff."""
translations = TranslatedFields(
title=models.CharField(
verbose_name=_('Title'),
max_length=256,
),
)


class DummyProfile(SimpleTranslationMixin, models.Model):
"""Just a dummy profile model for testing purposes."""
user = models.ForeignKey('auth.User')
Expand Down
11 changes: 11 additions & 0 deletions django_libs/tests/test_settings.py
Expand Up @@ -8,6 +8,16 @@

SITE_ID = 1

LANGUAGE_CODE = 'en'

LANGUAGES = [
('en', 'English'),
('de', 'Deutsch'),
]
USE_I18N = True
USE_L10N = True
USE_TZ = True


PROJECT_ROOT = os.path.dirname(__file__)

Expand Down Expand Up @@ -52,6 +62,7 @@
'django.contrib.sitemaps',
'django.contrib.sites',
'django_nose',
'hvad',
'mailer',
'south',
]
Expand Down
1 change: 0 additions & 1 deletion django_libs/tests/utils_email_tests.py
@@ -1,5 +1,4 @@
"""Tests for the email utils of ``django_libs``."""
from django.contrib.sites.models import Site
from django.core import mail
from django.test import TestCase

Expand Down
2 changes: 1 addition & 1 deletion django_libs/utils.py
Expand Up @@ -125,7 +125,7 @@ def handle_starttag(self, tag, attrs):
def handle_data(self, data):
"""Handles data between tags."""
# Only proceed with unignored elements
if not self.lasttag in self.ignored_elements:
if self.lasttag not in self.ignored_elements:
# Remove any predefined linebreaks
text = data.replace('\n', '')
# If there's some text left, proceed!
Expand Down
1 change: 1 addition & 0 deletions docs/conf.py
@@ -1,3 +1,4 @@
# flake8: noqa
# -*- coding: utf-8 -*-
#
# django-libs documentation build configuration file, created by
Expand Down
28 changes: 28 additions & 0 deletions docs/models_mixins.rst
@@ -1,6 +1,34 @@
Models Mixins
=============

TranslationModelMixin
---------------------

hvad's ``safe_translation_getter`` doesn't care about untranslated objects, so
we built this mixin to add some falllbacks

You can use this by inheriting the class::

from django.db import models

from hvad.models import TranslatableModel, TranslatedFields
from django_libs.models_mixins import TranslationModelMixin


class HvadModel(TranslationModelMixin, TranslatableModel):
translations = TranslatedFields(
title=models.CharField(
verbose_name=_('Title'),
max_length=256,
),
)

This mixin will automatically return the title field if its ``__unicode__``
function is called and it will always return a title string (no pk fallback or
anything like that needed). If there's no translation available in the current
language it searches for others.


SimpleTranslationMixin
----------------------

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Expand Up @@ -9,6 +9,7 @@ factory_boy>2.0.0
South

simple_translation
django-hvad

# ==============================================================
# Packages needed for running the tests. Needed by contributors.
Expand Down
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -28,5 +28,6 @@ def read(fname):
'beautifulsoup4>4.0.0',
'Pillow',
'South',
'django-hvad',
]
)

0 comments on commit a15f2a5

Please sign in to comment.