Giter VIP home page Giter VIP logo

django-hvad's Introduction

django-hvad package coverage build

Model translations made easy.

This project adds support for model translations in Django. It is designed to be unobtrusive, efficient and reliable. On the technical side, it uses an automatically created Translations Model to store translatable fields in arbitrary languages with a foreign key to the main model, enabling fast queries.

Started in 2011, hvad has grown mature and is now used on large scale applications.

Quick links:

Features

  • Simple - only 3 new queryset methods.
  • Natural - use Django ORM as usual, it just became language aware.
  • Fast - no additional queries for reads, just an inner join to an indexed key.
  • Complete - relationships, custom managers and querysets, proxy models, and abstract models.
  • Batteries included - translation-enabled forms and admin are provided.
  • Reliable - more than 300 test cases and counting. coverage build
  • Compatible with Django 1.8 to 1.11, running Python 2.7, 3.4, 3.5 or 3.6.

Django-hvad also features support for Django REST framework 3.1 or newer, including translation-aware serializers.

Example Uses

Declaring a translatable Book model:

class Book(TranslatableModel):
    author = models.ForeignKey(Author)
    release = models.Date()

    translations = TranslatedFields(
        title = models.CharField(max_length=250)
    )

Thus, only the title will vary based on the language. Release date and author are shared among all languages. Let's now create a Book instance:

# The recommended way:
book = Book.objects.language('en').create(
    author = Author.objects.get(name='Antoine de Saint Exupéry'),
    release = datetime.date(1943, 4, 6),
    title = "The Little Prince",
)

# Also works
book = Book(language_code='en')
book.author = Author.objects.get(name='Antoine de Saint Exupéry')
book.release = datetime.date(1943, 4, 6)
book.title = "The Little Prince"
book.save()

Providing some translations:

book.translate('fr')
book.title = "Le Petit Prince"
book.save()
book.translate('de')
book.title = "Der kleine Prinz"
book.save()

Every call to translate() creates a new translation from scratch and switches to that translation; save() only saves the latest translation. Let's now perform some language-aware queries:

Book.objects.all()

Compatible by default: returns all objects, without any translated fields attached. Starting from v1.0, default behavior can be overriden to work like next query:

Book.objects.language().all()

Returns all objects as translated instances, but only the ones that are translated into the currect language. You can also specify which language to get, using e.g.:

Book.objects.language("en").all()

Usual queryset methods work like they always did: let's get all books as translated instances, filtering on the title attribute, returning those that have Petit Prince in their French title, ordered by publication date (in their French edition):

Book.objects.language("fr").filter(title__contains='Petit Prince').order_by('release')

Other random examples:

# last German book published in year 1948
Book.objects.language("de").filter(release__year=1948).latest()

# other books from the same author as mybook. Cache author as well.
Book.objects.language().select_related('author').filter(author__books=mybook)

# books that have "Django" in their title, regardless of the language
Book.objects.language('all').filter(title__icontains='Django')

More examples in the quickstart guide.

Releases

Django-hvad uses the same release pattern as Django. The following versions are thus available:

  • Stable branch 1.7, available through PyPI and git branch releases/1.7.x.
  • Stable branch 1.8, available through PyPI and git branch releases/1.8.x.
  • Development branch 1.9, available through git branch master.

Stable branches have minor bugfix releases as needed, with guaranteed compatibility. See the installation guide for details, or have a look at the release notes.

Thanks to

Jonas Obrist (https://github.com/ojii) for making django-nani and for helping me with this project.

Kristian Øllegaard (https://github.com/KristianOellegaard/) for django-hvad and trusting me to continue the development.

django-hvad's People

Contributors

akx avatar andialbrecht avatar beniwohli avatar bertrandbordage avatar bradenmacdonald avatar chive avatar clelland avatar czpython avatar dnaranjo89 avatar eyvoro avatar fladi avatar icatalina avatar krisb78 avatar kristianoellegaard avatar meshy avatar mkoistinen avatar ojii avatar ollb avatar qris avatar rasca avatar semekh avatar shaib avatar spectras avatar sphericalhorse avatar stefanfoulis avatar superdmp avatar vstoykov avatar webjunkie avatar xordoquy avatar yakky avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

django-hvad's Issues

Integration with django-cms PlaceholderField plugin js editor

When integrating a django-cms PlaceholderField in a nani.models.TranslatableModel, the django-cms plugin_editor.js is unable to take the current language.
So when adding a new plugin, it get saved in the default language.
The following changeset:

Shows a possible integration way that works for me.
plugin_editor.js will try:

language = $('input[name=language]').attr("value");

Regards,
Bernardo

Proxy model raise bugs when getting translations model

I acknowledge that currently hvad/nani have no support for inheritance, but I believe we should gradually work on that. If the patch below has no drawback...
Patch

class TranslationManager(models.Manager):
###...
    @property
    def translations_model(self):
        """
                Get the translations model class
                """
        return self.model._meta.translations_model

to

class TranslationManager(models.Manager):
###...
    @property
    def translations_model(self):
        """
                Get the translations model class
                """
        return self.model.translations.related.model

Translated fields in admin fields = ( ... )

I have class, like this:

class Element(TranslatableModel):
     ...

    translations = TranslatedFields(
         name = models.CharField(max_length=45)
    )

How can I use translated field (name) in fields ? like this ...

class ElementAdmin(TranslatableAdmin):
    fields = ( ... , 'name' , ... )

(I want set order - of course it causes errors ... )

Ordering on translated fields

I have very simple models that I need to translate :

class Country(TranslatableModel):
    translations = TranslatedFields(
        name = models.CharField(_(u'name'), max_length=100)
    )

    def __unicode__(self):
        return self.safe_translation_getter('name', 'Country: %s' % self.pk)

    class Meta:
        ordering = ('name',)
        verbose_name = _(u"country")
        verbose_name_plural = _(u"countries")

The ordering fail because "ordering" refers to "name", a field that doesn't exist.

Issues when using django paginators

am trying to paginate a translatable model built using django-hvad, below is my code

    p = Paginator(Bonanza, 10)

    # get page number
    try:
        page = int(request.GET.get('page', '1'))

    except ValueError:
        page = 1

    try:
        bonz = p.page(page)

    except (EmptyPage, InvalidPage):
        bonz = p.page(p.num_pages)

    return {
        'objects'   : bonz.object_list,
        'page'      : bonz.number,
        'has_next'  : bonz.has_next()
    }

but its returning the following error

Resource does not expect any parameters.

Exception was: object of type 'TranslatableModelBase' has no len()

any ideas on how to resolve this issue? or if there is alternative ways of dealing with pagination when using django-hvad?

``language`` should be lazy

As querysets are lazy in Django, calling .language() should probably be lazy too (especially the call to get_language).

The reason for this is that model form definitions that want to use language break, as it will call get_language on form definition (start of server) instead of inside the request/response cycle.

Suggested feature: add support for select_related on TranslationAwareManager

Hello, this isn't really an "issue", but more like a support question. I am posting here b/c you don't have a mailing list and IRC isn't very reliable support channel. So first, let me describe my models:

class ModelA(TranslatableModel):
    code = CharField(max_length=3)

    translations = TranslatedFields(
        name = CharField(max_length=255)
    )

class ModelB(Model):
    modela = ForeignKey(ModelA)

class ModelC(Model):
    modelb = ForeignKey(ModelB)

My query looks like this:

objs = get_translation_aware_manager(ModelC).language().select_related().filter(...)

However, when I iterate through the objs in my template and call obj.modelb.modela.name it makes an additional db query to get the translation, so I am facing the 1+n db queries, which doesn't really scale well.
Normally, when I call language() on TranslatableModel it prefetches translations for the given language, but it seems like the translations for related objects aren't prefetched. Would it be possible to do this kind of prefetching?

Thank you very much!

Display error while using a PlaceholderField

I have a news model where we want to had the placeholders / plugin system. Translation part looks like this:

# Translated news fields
translations = TranslatedFields(
        # Editorial content
        title = models.CharField(_(u'news_title'), max_length=500, blank=False, null=False),
        short_desc = models.TextField(_(u'news_short_desc'), blank=True),
        # Placeholders (plugins)
        news_placeholder = PlaceholderField('news_placeholder')
)

I migrate the thing and the fields seem ok in the database. But when I try to add / modify I get the "you must use a translation aware manager, you can get one using nani.utils.get_translation_aware_manager" Error. I'm pretty sure it's coming for the django pluginholder mecanism but is there a way to fix this ?

Here's the stack trace

Environment:

Request Method: GET
Request URL: http://blinky.william.local:8030/admin/news/news/add/

Django Version: 1.3.1
Python Version: 2.7.2
Installed Applications:
['admin_tools',
 'admin_tools.theming',
 'admin_tools.menu',
 'admin_tools.dashboard',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.messages',
 'django.contrib.admin',
 'django.contrib.staticfiles',
 'cms',
 'menus',
 'mptt',
 'south',
 'cms.plugins.text',
 'cms.plugins.link',
 'cms.plugins.snippet',
 'cms.plugins.googlemap',
 'sekizai',
 'sorl.thumbnail',
 'reversion',
 'filer',
 'debug_toolbar',
 'easy_thumbnails',
 'cmsplugin_filer_image',
 'cmsplugin_filer_file',
 'cmsplugin_filer_folder',
 'cmsplugin_filer_teaser',
 'cmsplugin_filer_video',
 'django.contrib.webdesign',
 'multiuploader',
 'pagePlugins',
 'w_wysiwyg',
 'nani',
 'news',
 'pagePlugins.pageOptions']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'cms.middleware.multilingual.MultilingualURLMiddleware',
 'cms.middleware.page.CurrentPageMiddleware',
 'cms.middleware.user.CurrentUserMiddleware',
 'cms.middleware.toolbar.ToolbarMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware')

Traceback:

File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  111.                         response = callback(request, *callback_args, **callback_kwargs)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/django/contrib/admin/options.py" in wrapper
  307.                 return self.admin_site.admin_view(view)(*args, **kwargs)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  93.                     response = view_func(request, *args, **kwargs)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func
  79.         response = view_func(request, *args, **kwargs)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/django/contrib/admin/sites.py" in inner
  197.             return view(request, *args, **kwargs)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/django/db/transaction.py" in inner
  217.                 res = func(*args, **kwargs)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/reversion/revisions.py" in _create_on_success
  347.                     result = func(*args, **kwargs)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/reversion/admin.py" in add_view
  351.         return super(VersionAdmin, self).add_view(*args, **kwargs)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper
  28.             return bound_func(*args, **kwargs)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view
  93.                     response = view_func(request, *args, **kwargs)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func
  24.                 return func(self, *args2, **kwargs2)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/django/db/transaction.py" in inner
  217.                 res = func(*args, **kwargs)
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/django/contrib/admin/options.py" in add_view
  912.         adminForm = helpers.AdminForm(form, list(self.get_fieldsets(request)),
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/cms/admin/placeholderadmin.py" in get_fieldsets
  75.             fieldsets.append((self.get_label_for_placeholder(placeholder), {
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/cms/admin/placeholderadmin.py" in get_label_for_placeholder
  85.         return ' '.join([x.capitalize() for x in self.model._meta.get_field_by_name(placeholder)[0].verbose_name.split(' ')])
File "/home/ybroy/public_html/hydro-nouvelle/local/lib/python2.7/site-packages/nani/utils.py" in __call__
  53.                                    name)

Exception Type: WrongManager at /admin/news/news/add/
Exception Value: To access translated fields like 'news_placeholder' from an untranslated model, you must use a translation aware manager, you can get one using nani.utils.get_translation_aware_manager.

Proxy models don't work

Is there any way of using django proxy models with django-hvad?
I've got an error: no TranslatedFields found on <class 'Test'>, subclasses of TranslatableModel must define TranslatedFields.
But parent of Test has TranslatedFields and subcluss TranslatableModel.

How translate models with exists data

Hi, help me plz
I have model with data and i want to translate it with hvad and south migration

My model

class DeliveryCountry(models.Model):

    name = models.CharField(max_length=200)

I change model to

class DeliveryCountry(TranslatableModel):
    translations = TranslatedFields(
        name = models.CharField(max_length=200)
    )

How save exists data ?
South create migration with action to delete old name field and create new table to translations

Problem in admin (matching query does not exist.)

I have model with exist rows in db and i migrate to translate model

class DeliveryCountry(TranslatableModel):
    name = models.CharField(max_length=200, verbose_name=u'Название')

    translations = TranslatedFields(
        name=models.CharField(max_length=200, verbose_name=u'Название'),
    )

    class Meta:
        verbose_name = u'Страна'
        verbose_name_plural = u'Страны'

    def __unicode__(self):
        return self.lazy_translation_getter('name')

In admin.py

admin.site.register(DeliveryCountry)

And in admin in list items i get error

DoesNotExist at /admin/delivery/deliverycountry/
DeliveryCountryTranslation matching query does not exist.

TranslationQueryset.get_or_create fails to create

The get_or_create method is not overridden in TranslationQueryset; as a result, calling code like

Model.objects.language('en').get_or_create(**creation_args)

will fail, as the TranslationQueryset will defer to django's get_or_create, which will naively attempt to create a new TranslationModel with the creation args which were intended for the Translatable Model.

I have attached a set of test cases in a pull request (#19).

conflicts with django-polymorphic

Could django-hvad be made compatible with django-polymorphic, to allow a modelclass to subclass both hvad's TranslatableModel and django-polymorphic's PolymorphicModel?

According to the comments in hvad's code, it uses the same mechanism as django-polymorphic, but hvad and polymorphic appear to conflict: trying a

class DemoClass(PolymorphicModel, TranslatableModel):
    pass

First causes a metaclass inheritance error (the one discussed in ojii#39 and #38 ), but adding the noconflict.py trick mentioned there won't solve the actual problem, since both hvad and django-polymorphic want to have their custom manager as the default manager for the modelclass.

Any plans or suggestions to fix this conflict?

TranslatableModel cannot be abstract

post/models.py

from django.db import models
from django.core.urlresolvers import reverse
from nani.models import TranslatableModel, TranslatedFields
#from multilingual_model.models import MultilingualModel, MultilingualTranslation
from django.contrib.auth.models import User

class Reference(models.Model):
    pass

#class TagModel():

class Tag(TranslatableModel):
    translations = TranslatedFields(
        name    = models.CharField(max_length=255),
    slug    = models.SlugField(unique=True),
        )
    def __unicode__(self):
        return self.name
    #@models.permalink
    def get_absolute_url(self):
        #return ('post.views.PageDetail.as_view()', (), {
        #   'slug': self.slug,
        #   })
        return '/tag/{}'.format(self.slug)
    class Meta:
        ordering = ("slug",)

############################
class PublishedManager(models.Manager):
    def get_query_set(self):
        return super(self.__class__, self).get_query_set().filter(published=True)
############################

class Post(TranslatableModel):
    translations = TranslatedFields(
        title       = models.CharField(max_length=255),
    slug        = models.CharField(max_length=255, db_index=True, blank=True),
    description = models.CharField(max_length=255),
    published   = models.BooleanField(default=False),
    content     = models.TextField(),
        )
    tags        = models.ManyToManyField(Tag, blank=True)
    class Meta:
        abstract = True
    def __unicode__(self):
        return self.title

class Page(Post):
    #@models.permalink
    def get_absolute_url(self):
        #return ('post.views.PageDetail.as_view()', (), {
        #   'slug': self.slug,
        #   })
        return '/{}'.format(self.slug)
    def get_admin_url(self):
        return reverse('admin:{:s}_{:s}_change'.format(
            self._meta.app_label,
            #Remove 'published' to get to real Model
            self._meta.module_name.replace('published','')
        ), args = (self.pk,))
    class Meta:
        ordering = ("slug",)

class PublishedPage(Page):
    objects = PublishedManager()
    class Meta:
        proxy = True

class Entry(Post):
    translations = TranslatedFields(
        topics  = models.ManyToManyField(Page, related_name='entry_set', null=True, blank=True),
    authors     = models.ManyToManyField(User, blank=True),
    updated     = models.DateTimeField(
        #auto_now=True,
        null=True,
    ),

    )
    #@property
    #def topics(self):
    #   return self.categories
    @property
    def full_slug(self):
        return '{}/{:02d}/{}'.format(self.updated.year, self.updated.month, self.slug)
    class Meta:
        ordering = ("-updated",)
        pass

class PublishedEntry(Entry):
    objects = PublishedManager()
    def get_absolute_url(self):
        try:
            return self.news.get_absolute_url()
        except:
            return self.article.get_absolute_url()
    class Meta:
        proxy = True

class Article(Entry):
    references  = models.ManyToManyField(Reference, blank=True)
    def get_absolute_url(self):
        return '/article/{}'.format(self.full_slug)

class PublishedArticle(Article):
    objects = PublishedManager()
    class Meta:
        proxy = True

class News(Entry):
    def get_absolute_url(self):
        return '/news/{}'.format(self.full_slug)
    class Meta:
        verbose_name_plural = "news"

class PublishedNews(News):
    objects = PublishedManager()
    class Meta:
        proxy = True
##### error
bash -cl "/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Applications/PyCharm.app/helpers/pycharm/django_manage.py validate"
Traceback (most recent call last):
  File "/Applications/PyCharm.app/helpers/pycharm/django_manage.py", line 17, in <module>
    run_module(manage_file, None, '__main__')
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 180, in run_module
    fname, loader, pkg_name)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/Users/truongsinh/Sources/gabc_pro/manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/__init__.py", line 443, in execute_from_command_line
    utility.execute()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/__init__.py", line 382, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/base.py", line 196, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute
    output = self.handle(*args, **options)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/base.py", line 371, in handle
    return self.handle_noargs(**options)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/commands/validate.py", line 9, in handle_noargs
    self.validate(display_num_errors=True)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/base.py", line 266, in validate
    num_errors = get_validation_errors(s, app)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/validation.py", line 30, in get_validation_errors
    for (app_name, error) in get_app_errors().items():
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/loading.py", line 158, in get_app_errors
    self._populate()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/loading.py", line 64, in _populate
    self.load_app(app_name, True)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/loading.py", line 88, in load_app
    models = import_module('.models', app_name)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/utils/importlib.py", line 35, in import_module
    __import__(name)
  File "/Users/truongsinh/Sources/gabc_pro/post/models.py", line 34, in <module>
    class Post(TranslatableModel):
  File "/Users/truongsinh/Sources/gabc_pro/lib/django-hvad/nani/models.py", line 105, in __new__
    new_model = super_new(cls, name, bases, attrs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/base.py", line 99, in __new__
    new_class.add_to_class(obj_name, obj)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/base.py", line 219, in add_to_class
    value.contribute_to_class(cls, name)
  File "/Users/truongsinh/Sources/gabc_pro/lib/django-hvad/nani/models.py", line 80, in contribute_to_class
    create_translations_model(cls, name, self.meta, **self.fields)
  File "/Users/truongsinh/Sources/gabc_pro/lib/django-hvad/nani/models.py", line 49, in create_translations_model
    editable=False, null=True)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/fields/related.py", line 912, in __init__
    assert not to._meta.abstract, "%s cannot define a relation with abstract class %s" % (self.__class__.__name__, to._meta.object_name)
AssertionError: ForeignKey cannot define a relation with abstract class Post

Process finished with exit code 1

Respect settings.LANGUAGE_CODE as default language

The default language_code are always 'en-us', it would be much better if it did respect the settings.
I might have missed something in the documentation and would love to be proven wrong but until then, here is an example

models.py

class MyModel(TranslatableModel):
    shared_field = models.CharField(max_length=50)
    translations = TranslatedFields(
        name = models.CharField(max_length=50)
    )

instance = MyModel.objects.create(shared_field='foo', name='bar')

settings.py

LANGUAGE_CODE='sv-se'

LANGUAGES = (
    ('en-us', 'English'),
    ('sv-se', 'Swedish'),
)

dump.json

{
      "pk": 1,
      "model": "app.mymodel",
      "fields": {
          "shared_field": "foo"
      }
},
{
        "pk": 1,
        "model": "app.mymodeltranslation",
        "fields": {
           "name": "bar",
            "language_code": "en-us",
            "master": 1
        }
    },

Make hvad work with django 1.4's prefetch_related

Django 1.4 comes with a custom method: prefetch_related, wich workrs like select_related, but with a broader scope.

However, no matter how hard I try, I cannot make it work with translated models. Here's an example:

class OptionGroup(TranslatableModel):
    translations = TranslatedFields(
        name = models.CharField(_("Name of Option Group"), max_length=50,
            help_text=_("This will be the text displayed on the product page."))
    )
)

class Option(TranslatableModel):
    option_group = models.ForeignKey(OptionGroup, related_name="options")
    translations = TranslatedFields(
        display_name = models.CharField(_("Name displayed on store"), max_length=50)
    )

class ConfigurableProduct(models.Model):
    option_groups = models.ManyToManyField(OptionGroup)

Now, let's imagine that I want to display a configurable product, with all associated option groups and options, with the minimum number of queries:

configurable = ConfigurableProduct.objects.???.get(pk=1)
for group in configurable.option_groups.???:
    for option in group.options.???:
        print '%s %s' % (group.display_name, option.display_name)

Well, I'm aware this is not really a bug report, but I was wondering if you had an idea of the best way to proceed, or if they were any work to use prefetch_related?

Thank you for reading.

ImproperlyConfigured error when using fieldsets in admin.py

I have a news model that works perfeclty with hvad (Fr and En), but when it comes to add fieldsets in the admin.py:

...
fieldsets = (
('Editorial', {
'fields': ('title', 'subtitle')
}),
('Search filter', {
'classes': ('collapse',),
'fields': ('is_top_news', in_special_section', )
}),
)
...

I get this error:

ImproperlyConfigured at /admin/news/news/1/
'NewsAdmin.fieldsets[0][1]['fields']' refers to field 'title' that is missing from the form.

Which make sens, because the field don't belong to the News model. But, is there a way to access it ?

issue with googlebot

Hi,

I've implemented hvad models, it successfully serves pages to users, but googlebot crashes

I guess it misses the accept-language in the header

File "/home/me/.buildout/eggs/Django-1.4.2-py2.6.egg/django/db/models/query.py", line 366, in get
% self.model._meta.object_name)

DoesNotExist: InfoTranslation matching query does not exist.

can anyone point me to a workaround ? tx

Presentation of object in __unicode__ always return default value

On all my models after I get your fork of nani I get default value. Why? In standard nani dev0.5 I get correct value of translated field title. Now I have in admin pages for related fields only to select default for every item.

def unicode(self):
return smart_unicode(self.safe_translation_getter('title', "default"))

pip module broken (?)

have a look at this pseudo-shellshot:
pip install django-hvad
(add 'hvad' to INSTALLED_APPS)
./manage.py runserver
Error: No module named hvad
pip uninstall django-hvad
pip install -e git+git://github.com/KristianOellegaard/django-hvad.git#egg=django-hvad
./manage.py runserver
(works as expected)
pip uninstall django-hvad && pip install django-hvad
(change 'hvad' to 'nani' in settings.py)
./manage.py runserver
(server works, not sure about code)

tested on django 1.4.1, I cannot diagnose the problem but the pypi module is messed up

How to get a translated value for a specified language?

I'm trying to get Django-CMS's language chooser to work with my TranslatableModel.

I'm trying to pass a language to my get_absolute_url function in order for it to get a translated slug:

def get_slug(self, language):
    # What to do with language?
    return self.lazy_translation_getter('slug')

def get_absolute_url(self, language = None):
    return reverse('events.detail', args = [], kwargs = { 'slug': self.get_slug(language)} )

How can I get a translated value for 'slug' in the language I pass in? I tried to use the safe and lazy translation getters but they only take the language of the request into account, while I need to get the value for other languages too.

Feature Request: section untranslatable fields off from the rest in admin

Is it possible to section untranslatable fields off from the rest ? For example: Now, i have, two cards with two languages, and each card have both types of fields (translatable and untranslatable), it would be great to achieve something like: Firstly, untranslatable fields, and then, below, cards with languages and translatable fields.

TranslationManager.language() does'nt call get_query_set()

Hi,

It's written in the doc that TranslationManager.language() calls get_query_set().

However, I must be missing something, because I cannot find a trace of this call.

Because of that, I cannot use custom managers.

class StoreItemManager(TranslationManager):
    def get_query_set(self):
        qs = super(StoreItemManager, self).get_query_set()
        return qs.filter(display_in_store=True)

class CatalogItem(TranslatableModel):
    objects = TranslationManager()
    store_items = StoreItemManager()
    display_in_store = models.BooleanField(_)
items = CatalogItem.store_items.language()

The latest call returns all objects, whatever the value of display_in_store is. Is this a bug, or is there a different way of doing it?

Thank you.

Django 1.2 not supported

Hi,

The django-hvad documentation (and setup.py) claim that it only requires Django>=1.2; however, when trying to test with Django 1.2 we get:

$ python manage.py test
Traceback (most recent call last):
  File "manage.py", line 16, in <module>
    execute_manager(settings)
    ...
  File ".../nani/views.py", line 2, in <module>
    from django.views.generic.edit import UpdateView
ImportError: No module named edit

Generic views (including Edit views) are a Django 1.3 feature. I suppose the right fix is an update to documentation and setup.py.

Thanks,
Shai.

How to include translated model when using select_related?

I'm trying to use select_related on some translated models in order to reduce the number of queries needed when loading a page on my site.

I was able to get select_related working (see mstarinc/django-hvad@cf66fec33038162b26a6d3cc92a7dabcd3f690df ), but it only selects the shared model across relationships, and doesn't include related translated models. So when I later try to access translated fields across a relation, it generates a new query for each object.

Would someone mind commenting on my commit and giving me some guidance as to what I will have to change to get this fully working?

Here's the setup I have:

class Location(TranslatableModel):
    """ A location (e.g. a venue where an event is held. """
    city = models.CharField(max_length=30, blank=True)
    country = models.CharField(max_length=2, blank=True, choices=common_fields.COUNTRY_CHOICES)

    translations = TranslatedFields(
        name = models.CharField(max_length=128, blank=True),
    )

class Event(TranslatableModel):
    event_type = models.ForeignKey(EventType, blank=True, null=True)
    date = models.DateField()
    location = models.ForeignKey(Location, blank=True, null=True)

    translations = TranslatedFields(
        name = models.CharField(max_length=128),
        description = models.TextField(blank=True, null=True),
    )

What I want to do is

all_events = Event.objects.language().select_related('event_type', 'location').all()

After I modified django-hvad, the above query works fine and properly retrieves the related objects, but the Location objects are untranslated, so if I do something like [e.location.name for e in all_events], it generates an extra query for every Event object. If I access 'location.name' using safe_translation_getter, it returns None, and if I use lazy_translation_getter, it generates 3 queries per Event object, which is even worse (2 existence queries, and one to get the name).

Caught DoesNotExist while rendering: mymodel matching query does not exist.

i got this if a create object with a inline item in one language ex : english ( but not the equivalant in french)

and after i change the language of my admin in django to : french

and re edit the same item ( since we change the language the tab will be pre-select in the current admin language)

and the equivalent doesnt exist so it fail.

maybe not clear i try my best to explain.
Maybe i should look for FallbackQueryset ( to use it in my TranslatableStackedInline ) ?

get an instance by searching all languages, not only the specified

Motivation: I have a multilingual article with translatable slug, when given a slug, I want to get exactly the article in particular language.

E.g.: I have an article call "About Us" with slug "about" in English and "Giới thiệu" with slug "gioi-thieu" in Vietnamese. For the sake of SEO, it was advised that we have different permanent URL for a content in different languages thus,

www.gabc.pro/about
www.gabc.pro/gioi-thieu

is a good practice. When user goes to, for example, www.gabc.pro/gioi-thieu, I would like to get the instance in Vietnamese, but I cannot get it anywhere but in instance.language_code. Thus I propose the solution below (note I am too lazy to fork and pull, and also I prefer tabs to 4-space)

#class TranslationQueryset
    def get_unique(self, *args, **kwargs):
        newargs, newkwargs = self._translate_args_kwargs(*args, **kwargs)
        return QuerySet.get(self, *newargs, **newkwargs)

    def language(self, language_code=None):
        if not language_code:
            language_code = get_language()
        self._language_code = language_code
        if language_code == 'all':
            return self
        return self.filter(language_code=language_code)

#views.py
Object.language("all").get_unique(slug="gioi-thieu")

Implement nonconflict for multiple inheritance

When model inherits from TranslatableModel and other abstract class this causes an error

TypeError: Error when calling the metaclass bases metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

Here is one possible solution: ojii#39

Suggested feature: generic relation that prefetch translations

I find out hvad problem with generic relations. For instance I have two models Quote and Author (translated model). Quote is related to Author by generic relation. Problem is if you try get list of quotes with prefetched authors. Quotes.objects.prefetch_related('originator')

Hvad in this case returns non-translated object, you can't access translated attributs. For this reason prefetching is useless. So I created custom TranslationGenericForeignKey, which respects translation objects. I don't know if this solution is valid.

Example source: http://martinsvoboda.blogspot.com/2012/11/django-generic-relation-prefetches-hvad.html

bulk_create does not work

Hello,

It seems like the bulk_create interface on object is not working, I tried to fork and work on a fix but am not sure how to return a raw insert statement for translatable & compile it with parameters to combine it with bulk_create

any advise?

nani.models.TranslatableModel cannot have proxy models

from django.db import models
from django.core.urlresolvers import reverse
from nani.models import TranslatableModel, TranslatedFields, TranslationManager

from multilingual_model.models import MultilingualModel, MultilingualTranslation

from django.contrib.auth.models import User

class Reference(models.Model):
pass

class TagModel():

class Tag(TranslatableModel):
translations = TranslatedFields(
name=models.CharField(max_length=255),
slug=models.SlugField(unique=True),
)

def __unicode__(self):
    return self.name

#@models.permalink
def get_absolute_url(self):
    #return ('post.views.PageDetail.as_view()', (), {
    #   'slug': self.slug,
    #   })
    return '/tag/{}'.format(self.slug)

class Meta:
    ordering = ("slug",)

class PublishedManager(TranslationManager):
def get_query_set(self):
return super(self.class, self).get_query_set().filter(published=True)

############################

class Page(TranslatableModel):
translations = TranslatedFields(
title=models.CharField(max_length=255),
slug=models.CharField(max_length=255, db_index=True, blank=True),
description=models.CharField(max_length=255),
published=models.BooleanField(default=False),
content=models.TextField(),
)
tags = models.ManyToManyField(Tag, blank=True)

def __unicode__(self):
    return self.title

#@models.permalink
def get_absolute_url(self):
    #return ('post.views.PageDetail.as_view()', (), {
    #   'slug': self.slug,
    #   })
    return '/{}'.format(self.slug)

def get_admin_url(self):
    return reverse('admin:{:s}_{:s}_change'.format(
        self._meta.app_label,
        #Remove 'published' to get to real Model
        self._meta.module_name.replace('published', '')
    ), args=(self.pk,))

class Meta:
    ordering = ("slug",)

class PublishedPage(Page):
objects = PublishedManager()
#objects = Page.objects
class Meta:
proxy = True

class Entry(TranslatableModel):
translations = TranslatedFields(
title=models.CharField(max_length=255),
slug=models.CharField(max_length=255, db_index=True, blank=True),
description=models.CharField(max_length=255),
published=models.BooleanField(default=False),
content=models.TextField(),
topics=models.ManyToManyField(Page, related_name='entry_set', null=True, blank=True),
authors=models.ManyToManyField(User, blank=True),
updated=models.DateTimeField(
#auto_now=True,
null=True,
),

    )
tags = models.ManyToManyField(Tag, blank=True)

def __unicode__(self):
    return self.title

#@property
#def topics(self):
#   return self.categories
@property
def full_slug(self):
    return '{}/{:02d}/{}'.format(self.updated.year, self.updated.month, self.slug)

class Meta:
    ordering = ("-updated",)
    pass

class PublishedEntry(Entry):
objects = PublishedManager()

def get_absolute_url(self):
    try:
        return self.news.get_absolute_url()
    except:
        return self.article.get_absolute_url()

class Meta:
    proxy = True

class Article(Entry):
references = models.ManyToManyField(Reference, blank=True)

def get_absolute_url(self):
    return '/article/{}'.format(self.full_slug)

class PublishedArticle(Article):
objects = PublishedManager()

class Meta:
    proxy = True

class News(Entry):
def get_absolute_url(self):
return '/news/{}'.format(self.full_slug)

class Meta:
    verbose_name_plural = "news"

class PublishedNews(News):
objects = PublishedManager()

class Meta:
    proxy = True

bash -cl "/Library/Frameworks/Python.framework/Versions/2.7/bin/python2.7 /Applications/PyCharm.app/helpers/pycharm/django_manage.py validate"
Traceback (most recent call last):
File "/Applications/PyCharm.app/helpers/pycharm/django_manage.py", line 17, in
run_module(manage_file, None, 'main')
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 180, in run_module
fname, loader, pkg_name)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/runpy.py", line 72, in _run_code
exec code in run_globals
File "/Users/truongsinh/Sources/gabc_pro/manage.py", line 10, in
execute_from_command_line(sys.argv)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/init.py", line 443, in execute_from_command_line
utility.execute()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/init.py", line 382, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/base.py", line 196, in run_from_argv
self.execute(_args, *_options.dict)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/base.py", line 232, in execute
output = self.handle(_args, *_options)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/base.py", line 371, in handle
return self.handle_noargs(**options)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/commands/validate.py", line 9, in handle_noargs
self.validate(display_num_errors=True)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/base.py", line 266, in validate
num_errors = get_validation_errors(s, app)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/core/management/validation.py", line 30, in get_validation_errors
for (app_name, error) in get_app_errors().items():
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/loading.py", line 158, in get_app_errors
self._populate()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/loading.py", line 64, in _populate
self.load_app(app_name, True)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/loading.py", line 88, in load_app
models = import_module('.models', app_name)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/utils/importlib.py", line 35, in import_module
import(name)
File "/Users/truongsinh/Sources/gabc_pro/post/models.py", line 69, in
class PublishedPage(Page):
File "/Users/truongsinh/Sources/gabc_pro/lib/django-hvad/nani/models.py", line 141, in new
"TranslatableModel must define TranslatedFields." % new_model
django.core.exceptions.ImproperlyConfigured: No TranslatedFields found on <class 'post.models.PublishedPage'>, subclasses of TranslatableModel must define TranslatedFields.

Process finished with exit code 1

Default language

Is there any way for setting any language as default. So if some objects don't have a translation on current language they are queried from DB for default language.

attrs['language_code'] of translation model should have choices

#nani/models.py
def create_translations_model(model, related_name, meta, **fields):
    #...
    attrs['language_code'] = models.CharField(max_length=15, db_index=True)
    #...

should be

#nani/models.py
def create_translations_model(model, related_name, meta, **fields):
    #...
    attrs['language_code'] = models.CharField(max_length=15, db_index=True, choices=settings.LANGUAGES)
    #...

Well. it might be trivial, but imagine if I want to have an admin view of the translation itself, it may help a lot!

#[myapp]/admin.py
admin.site.register(Page)
admin.site.register(Page.translations.related.model, PageAdmin)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.