2011-07-27 11 views
7

Dado es un modelo de Django llamado BlogPost. Al principio, está codificado sin un Meta.verbose_name. En ./manage.py syncdb vez, se crea automáticamente ContentType con un nombre "publicación de blog". En algún momento posterior, se agrega Meta.verbose_name de "Publicación de blog".Cuando cambia el nombre detallado, ¿cómo actualizo automáticamente el ContentType de un modelo?

Ahora hay una discrepancia: ContentType se llama "entrada de blog", mientras que el modelo pasa el nombre descriptivo de "Blog post", esta diferencia se muestra en todo marco usando las relaciones genéricas, por ejemplo, en los comentarios 'admin. Me gustaría corregir esta situación cambiando el nombre de ContentType, sin embargo, no me gustaría hacerlo a mano (por razones obvias) o mediante una migración (ya que no migro nada más, Meta.verbose_name es solo un cambio de código).

¿Cómo actualizarías el nombre ContentType al Meta.verbose_name cambiar?

Respuesta

10

Respondiendo a propia pregunta: He logrado hacer esto con una pequeña señal post_migrate. Si no está utilizando el Sur, probablemente sea perfectamente posible utilizar la señal post_syncdb de la misma manera. Cualquier comentario sobre este código es apreciado.

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

¡Funciona muy bien para mí, gracias! Por cierto, probablemente deberías marcar esto como una respuesta :) – Dave

+0

Si usas caracteres especiales en tu nombre detallado, quieres usar 'new_name = cl._meta.verbose_name.decode ('utf-8')' –

+0

Si eres preguntándose como yo ** dónde poner este código **, el nivel de aplicación '__init __. py' es el lugar. –

1

Otro enfoque consiste en redefinir ContentType.__str__ método, ya que se parece a esto:

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) 

Por lo tanto, se puede escribir de nuevo, si es que no es necesario algún tipo de compatibilidad con versiones anteriores:

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 

Es un poco complicado, pero creo que es más sencillo. Tenga en cuenta que, dado que se utiliza Django 1.4.1 force_text en lugar de force_unicode.

Cuestiones relacionadas