Когда verbose_name изменяется, как мне автоматически обновить ContentType модели? - PullRequest
7 голосов
/ 27 июля 2011

Дана модель Джанго под названием BlogPost.Сначала это кодируется без Meta.verbose_name.Во время ./manage.py syncdb автоматически создается ContentType с именем запись в блоге .В какой-то более поздний момент времени добавляется Meta.verbose_name из " Пост блога ".

Теперь есть расхождение: ContentType называется " пост блога ", хотя модель идет под подробным именем" Запись в блоге", это различие проявляется в любой среде, использующей общие отношения, например, в комментариях администратора.Я хотел бы исправить эту ситуацию, изменив имя ContentType, однако я бы не хотел делать это ни вручную (по понятным причинам), ни с помощью миграции (поскольку я больше ничего не переношу, Meta.verbose_name - это просто изменение кода).

Как бы вы обновили имя ContentType при изменении Meta.verbose_name?

Ответы [ 2 ]

10 голосов
/ 27 июля 2011

Отвечая на собственный вопрос: мне удалось сделать это с небольшим сигналом post_migrate. Если вы не используете Юг, возможно, вполне возможно использовать сигнал post_syncdb таким же образом. Любые комментарии к этому коду приветствуются.

from django.contrib.contenttypes.models import ContentType
from django.utils.functional import Promise

from south.signals import post_migrate 
# or if using django >=1.7 migrations:
# from django.db.models.signals import post_migrate

def update_contenttypes_names(**kwargs):
    for c in ContentType.objects.all():
        cl = c.model_class()
        # Promises classes are from translated, mostly django-internal models. ignore them.
        if cl and not isinstance(cl._meta.verbose_name, Promise):
            new_name = cl._meta.verbose_name
            if c.name != new_name:
                print u"Updating ContentType's name: '%s' -> '%s'" % (c.name, new_name)
                c.name = new_name
                c.save()

post_migrate.connect(update_contenttypes_names, dispatch_uid="update_contenttypes")
1 голос
/ 07 октября 2012

Другой подход заключается в переопределении метода ContentType.__str__, который выглядит следующим образом:

def __str__(self):
    # self.name is deprecated in favor of using model's verbose_name, which
    # can be translated. Formal deprecation is delayed until we have DB
    # migration to be able to remove the field from the database along with
    # the attribute.
    #
    # We return self.name only when users have changed its value from the
    # initial verbose_name_raw and might rely on it.
    model = self.model_class()
    if not model or self.name != model._meta.verbose_name_raw:
        return self.name
    else:
        return force_unicode(model._meta.verbose_name)

Итак, вы можете переписать его, если вам не нужна какая-либо обратная совместимость:

from django.contrib.contenttypes.models import ContentType
from django.utils.encoding import force_unicode

def contenttype_as_str(self):
    return force_unicode(self.model_class()._meta.verbose_name)

ContentType.__str__ = contenttype_as_str

Это немного сложно, но я считаю, что это более просто.Обратите внимание, что, поскольку Django 1.4.1 force_text используется вместо force_unicode.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...