Django parler TranslatableSlugMixin переводит с английского на другой язык, но после перевода не может быть переведен обратно возвращается 404
Я использую Django CMS с Django Parler и столкнулся с проблемой, которая сводит меня с ума, поэтому, если кто-нибудь сможет помочь, это будет очень цениться!
Итак, я создаю простое приложение для блога, в котором в качестве переводимого поля есть слаг. Вот упрощенная модель:
from parler.models import TranslatableModel, TranslatedFields
class Article(TranslatableModel):
...
translations = TranslatedFields(
...
slug = models.SlugField(_('slug'), max_length=255, blank=True, allow_unicode=True),
meta = {'unique_together': (('language_code', 'slug'),)}
)
...
def get_absolute_url(self):
return reverse('blog:article_detail', kwargs={'slug': self.slug})
Вот ссылки:
from django.conf.urls import include, url
from .views import ArticleDetailView
urlpatterns = [
...
url(r'^(?P<slug>\w[-\w]*)/$', ArticleDetailView.as_view(), name='article_detail'),
]
И, наконец, вот мнение:
from django.views.generic import DetailView
from parler.views import TranslatableSlugMixin
from .models import Article
class ArticleDetailView(TranslatableSlugMixin, DetailView):
model = Article
template_name = 'blog/_article.html'
Я создал статью на английском, французском и немецком языках, с разными ссылками для каждого языка, давайте назовем их так:
/en/blog/english-slug
/fr/blog/french-slug
/de/blog/german-slug
Я могу перейти ко всем этим правильно, но в Django CMS вверху есть языковое меню, которое на английской странице показывает ссылки в виде:
/en/blog/english-slug
/fr/blog/english-slug
/de/blog/english-slug
Это нормально, так как именно это обрабатывает TranslatableSlugMixin в представлении (см. Здесь http://django-parler.readthedocs.io/en/latest/api/parler.views.html).
Поэтому, когда я нажимаю одну из ссылок (скажем, французскую), представление правильно находит правильную статью и перенаправляет меня на правильный URL-адрес. Итак, нажав:
/fr/blog/english-slug
Принял меня правильно, чтобы:
/fr/blog/french-slug
Но здесь все идет не так. Теперь я хочу вернуться на английскую страницу, которая отображается как:
/en/blog/french-slug
Но когда я нажимаю на ссылку, она переходит к 404. Это то же самое, если я перехожу на немецкий URL с французского. Однако, если я сразу перейду с английского на немецкий, это сработает.
Извините, я знаю, что объяснение сбивает с толку, но кажется, что перевод работает в одну сторону с базового / стандартного на другой язык, но не работает правильно при переключении между языками или обратно на базовый / по умолчанию.
Конечно, TranslatableSlugMixin разработан, чтобы это произошло?! Так я что-то здесь упускаю?
Любая помощь приветствуется. Рад предоставить больше информации, если это необходимо.
Спасибо
1 ответ
Итак, я выяснил, как сделать эту работу, и оказалось, что это сочетание вещей...
Использование Django CMS по умолчанию было ошибкой:
{% language_chooser "menu/language_chooser.html" %}
Это приводит к URL-адресам, которые я описал выше:
/en/blog/english-slug /fr/blog/english-slug /de/blog/english-slug
Чтение документации Django Parler привело меня к использованию их языкового меню навигации:
{% for lang_code, title in LANGUAGES %} {% get_language_info for lang_code as lang %} {% get_translated_url lang_code as tr_url %} {% if tr_url %}<li{% if lang_code == LANGUAGE_CODE %} class="is-selected"{% endif %}><a href="{{ tr_url }}" hreflang="{{ lang_code }}">{{ lang.name_local|capfirst }}</a></li>{% endif %} {% endfor %}
Это приводит к URL-адресам, указывающим на правильное местоположение:
/en/blog/english-slug /fr/blog/french-slug /de/blog/german-slug
Чтобы сработала навигация Django Parler, мне нужно было обновить get_absolute_url() в модели, чтобы обрабатывать разные языки. Я сделал это следующим образом:
from django.utils.translation import get_language from parler.models import TranslatableModel, TranslatedFields class Article(TranslatableModel): ... def get_absolute_url(self): language = get_language() if self.has_translation(language): slug = self.safe_translation_getter('slug', language_code=language) return reverse('blog:article_detail', kwargs={'slug': slug}) # no translation so fallback to all article list return reverse('blog:article_list')
Уф! Это была головная боль! Надеюсь, это поможет кому-то еще в будущем!
PS Во время моего исследования я наткнулся на это приложение для блога, которое кажется действительно замечательным:
https://github.com/nephila/djangocms-blog
Это помогло мне добраться до сути этого кошмара!
ОБНОВИТЬ
Глядя на get_absolute_url() в djangocms-blog (ссылка выше), у них гораздо лучшее решение проблемы. Их реализация:
from django.utils.translation import get_language
from parler.models import TranslatableModel, TranslatedFields
class Article(TranslatableModel):
...
def get_absolute_url(self, lang=None):
if not lang or lang not in self.get_available_languages():
lang = self.get_current_language()
if not lang or lang not in self.get_available_languages():
lang = get_language()
with switch_language(self, lang):
slug = self.safe_translation_getter('slug', language_code=lang, any_language=True)
return reverse('blog:article_detail', kwargs={'slug': slug})
Спасибо Нефила, это спасло меня от многих ругательств и разочарований:)