Русские имена приложений и breadcrumbs в админке Django

28 Июл
2011

Если вы используете Django админку, и хоть раз пробовали перевести имя приложения на русский язык, то для вас не станет сюрпризом отсутствие стандартного, предусмотренного разработчиками решения. В сети можно найти информацию, посвященную этой проблемы. Некоторые решения отлично работают, хоть и представляются слишком трудоемкими, другие ломают нативные джанговские тесты. Однако я не нашел ни одного простого решения, которое позволило бы изменить имя приложения в breadcrumbs. Итак давайте посмотрим на внутренности админки и на то как можно решить нашу проблему. image Всего в джанго 29 шаблонов, использующих breadcrumbs, это легко проверить выполнив из корневого каталога фреймворка: grep -R "{% block breadcrumbs %}" . | nl Поэтому пришлось отказаться от переписывания стандарнтых шаблонов и обратить свое внимание на другие места, в котрых можно переопределить все и сразу. Таким местом оказался модуль admin.py внутри приложения, потому что через его функцию admin.site.register проходят все модели которые будут отображаться в админке. Так что если обернуть ее в свой декоратор, то можно сразу в одном месте воздействовать на все зарегистрированные модели. Все казалось просто – перегрузить несколько функций, атрибутов и дело сделано, но подвох оказался в том, что в разных шаблонах по разному определяется app_label. Так, например в app_index.html передается список app_list, у каждого элемента которого есть аттрибут name, в шаблон change_form.html передается сразу app_label. Поэтому в представленном вашему вниманию решении пришлось использовать несколько хаков. Итак, от слов перейдем к коду: from django.db.models.base import ModelBase from django.core.urlresolvers import resolve class AppLabelRenamer(object): ''' Переименовывает имя приложения и breadcrumbs в админке. ''' def __init__(self, native_app_label, app_label): ''' self.module служит для отсеивания моделей других приложений. ''' self.native_app_label = native_app_label self.app_label = app_label self.module = '.'.join([native_app_label, 'models']) class string_with_realoaded_title(str): ''' Класс для имени нашего приложения. Перегружает метод title, что впоследствии приводит к переименованию приложения. Спасибо Ionel Maries Cristian ''' def __new__(cls, value, title): instance = str.__new__(cls, value) instance._title = title return instance def title(self): return self._title __copy__ = lambda self: self __deepcopy__ = lambda self, memodict: self def rename_app_label(self, f): ''' Изменяет имя приложения и breadcrumbs ''' app_label = self.app_label def rename_breadcrumbs(f): def wrap(self, *args, **kwargs): extra_context = kwargs.get('extra_context', {}) extra_context['app_label'] = app_label kwargs['extra_context'] = extra_context return f(self, *args, **kwargs) return wrap def wrap(model_or_iterable, admin_class=None, **option): ''' ''' if isinstance(model_or_iterable, ModelBase): model_or_iterable = [model_or_iterable] for model in model_or_iterable: if model.__module__ != self.module: continue if admin_class is None: admin_class = type(model.__name__+'Admin', (admin.ModelAdmin,), {}) admin_class.add_view = rename_breadcrumbs(admin_class.add_view) admin_class.change_view = rename_breadcrumbs(admin_class.change_view) admin_class.changelist_view = rename_breadcrumbs(admin_class.changelist_view) model._meta.app_label = self.string_with_realoaded_title( self.native_app_label, self.app_label) return f(model, admin_class, **option) return wrap def rename_app_index(self, f): ''' Изменяет breadcrumb для имени приложения в app_index.html Здесь же можно изменить h1 заголовок, добавив в extra_content {'title': self.app_label} ''' def wrap(request, app_label, extra_context=None): requested_app_label = resolve(request.path).kwargs.get('app_label', '') if requested_app_label and requested_app_label == self.native_app_label: app_label = self.string_with_realoaded_title(self.native_app_label, self.app_label) else: app_label = requested_app_label return f(request, app_label, extra_context=None) return wrap def main(self): ''' Оборачивает стандартные функции нашими декораторами. ''' admin.site.register = self.rename_app_label(admin.site.register) admin.site.app_index = self.rename_app_index(admin.site.app_index) # Пример использования, где exampleapp имя нашего приложения. AppLabelRenamer(native_app_label=u'simplelms', app_label=u'Блог').main() Осталось только вставить сорцы в admin.py вашего приложения, подставив свои аргументы (native_app_label и app_label) в конструктор класса и запустив main(). Класс string_with_realoaded_title взят отсюда.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх