当verbose_name更改时,如何自动更新模型的ContentType?

时间:2011-07-27 15:29:37

标签: django django-models django-contenttypes

给出一个名为 BlogPost 的Django模型。首先,它的编码没有Meta.verbose_name。在./manage.py syncdb时间,会自动创建名为“博客帖子”的ContentType。在稍后的某个时间点,会添加“博客帖子Meta.verbose_name

现在存在差异:ContentType被称为“博客帖子”,而模型的详细名称为“博客帖子”,这种差异在使用通用关系的任何框架中显示,例如在评论'管理员。我想通过更改ContentType的名称来纠正这种情况,但是,我不想手动(出于显而易见的原因)或通过迁移(因为我不迁移任何其他内容) ,Meta.verbose_name只是代码更改。

ContentType更改后,您如何更新Meta.verbose_name的名称?

2 个答案:

答案 0 :(得分:10)

回答自己的问题:我设法通过一个小的post_migrate信号来做到这一点。如果您不使用South,则可能完全可以以相同的方式使用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 :(得分:1)

另一种方法是覆盖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

相关问题