【问题标题】:When verbose_name changes, how do I auto-update a model's ContentType?当 verbose_name 更改时,如何自动更新模型的 ContentType?
【发布时间】:2011-07-27 15:29:36
【问题描述】:

Given 是一个名为 BlogPost 的 Django 模型。起初,它的编码没有Meta.verbose_name。在./manage.py syncdb 时间,会自动创建一个名为“blog post”的ContentType。稍后,会添加“博文”的Meta.verbose_name

现在有一个差异:ContentType 被称为“blog post”,而模型的详细名称为“Blog post”,显示了这种差异在任何使用通用关系的框架中,例如在 cmets 的管理员中。我想通过更改ContentType 的名称来纠正这种情况,但是,我不想手动(出于显而易见的原因)或通过迁移(因为我不迁移其他任何东西,@ 987654328@只是代码更改)。

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

【问题讨论】:

    标签: django django-models django-contenttypes


    【解决方案1】:

    回答自己的问题:我已经设法用一个小的post_migrate 信号做到了这一点。如果您不使用 South,则完全有可能以相同的方式使用 post_syncdb 信号。对此代码的任何 cmet 表示赞赏。

    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")
    

    【讨论】:

    • 非常适合我,谢谢!顺便说一句,您可能应该将此标记为答案:)
    • 如果您在详细名称中使用特殊字符,您想使用new_name = cl._meta.verbose_name.decode('utf-8')
    • 如果你像我一样想把这段代码放在哪里,那么应用级的__init__.py就是这个地方。
    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2012-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-27
      • 2015-05-02
      • 1970-01-01
      • 2018-05-18
      • 2013-09-22
      相关资源
      最近更新 更多