2011-07-27 14 views
7

Verilen, BlogPost adlı bir Django modelidir. İlk başta, Meta.verbose_name olmadan kodlanmıştır. ./manage.py syncdb zamanında, "blog yazısı" isimli bir ContentType otomatik olarak oluşturulur. Daha sonraki bir zaman noktasında, "Blog yayını" un Meta.verbose_name eklenmiştir.Verbose_name değiştiğinde, bir modelin ContentType'ını nasıl otomatik güncellerim?

Şimdi bir tutarsızlık: ContentType "blog yazısı" denir, model "blog yazı" nin ayrıntılı adıyla giderken, bu fark, örneğin jenerik ilişkileri kullanarak herhangi çerçevede gösterilir yorumlarda 'admin. ContentType'un adını değiştirerek bu durumu düzeltmek istiyorum, ancak bunu el ile (açık nedenlerle) veya bir geçişle yapmak istemem (başka bir şey aktarmadığımdan, Meta.verbose_name sadece bir kod değişikliği).

Meta.verbose_name değiştirilmeden ContentType numarasını nasıl güncelleştirirsiniz?

cevap

10

Kendi sorusunu yanıtlama: Bunu küçük bir post_migrate sinyaliyle yapmayı başardım. Güney'i kullanmıyorsanız, muhtemelen post_syncdb sinyalini aynı şekilde kullanmak mümkün olabilir. Bu kod hakkında herhangi bir yorum takdir edilmektedir. Böyle göründüğü

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

Benim için harika çalışıyor, thx! BTW, muhtemelen bunu bir cevap olarak işaretlemelisiniz :) – Dave

+0

Eğer ayrıntılı isminizde özel karakter kullanırsanız, 'new_name = cl._meta.verbose_name.decode ('utf-8')' –

+0

benim gibi merak ediyorum ** bu kodu nereye koyacağınızı **, uygulama düzeyinde '__init __. py' yer. –

1

başka bir yaklaşım, ContentType.__str__ yöntemi geçersiz şudur:

: Yani

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) 

Eğer geriye dönük uyumluluk çeşit gerekmiyorsa, sen bunu yeniden yazabilirsiniz

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 

Biraz zor, ama daha kolay olduğuna inanıyorum. Not, force_unicode yerine Django 1.4.1 force_text kullanıldığı için.