2010-12-07 10 views
55

Bir konu adı ve bunların baş harflerini içermek istediğim bir modelim var. (Veri biraz anonimleştirilerek baş harfleri tarafından takip edilmektedir.)Django Model Alanı Varsayılan Olarak Aynı Modeldeki Başka Bir Alana Dayalı

Şu anda,

class Subject(models.Model): 

    name = models.CharField("Name", max_length=30) 
    def subject_initials(self): 
     return ''.join(map(lambda x: '' if len(x)==0 else x[0], 
          self.name.split(' '))) 
    # Next line is what I want to do (or something equivalent), but doesn't work with 
    # NameError: name 'self' is not defined 
    subject_init = models.CharField("Subject Initials", max_length=5, default=self.subject_initials) 

yazdığı son çizgi ile belirtildiği gibi, ben baş harfleri aslında depolanır var edebilmek tercih edeceğini Bir alan olarak veritabanı (addan bağımsız), ancak ad alanına dayalı bir varsayılan değerle başlatılır. Ancak, django modelleri bir 'kendime' sahip görünmüyor gibi sorunlar yaşıyorum.

Satırı subject_init = models.CharField("Subject initials", max_length=2, default=subject_initials) olarak değiştirirseniz, syncdb'yi yapabilirim, ancak yeni konular oluşturamıyorum.

Bu, django'da mümkündür, bir callable işlevine sahip olmak, başka bir alanın değerine bağlı olarak bazı alanlara varsayılan değer verir mi?

(Merak ettiğim için, mağaza başlangıçlarımı ayrı ayrı ayırmak istememin sebebi, garip soyadlarının izlediklerimden farklı olabildiği nadir durumlarda ortaya çıkmaktadır. Örneğin, bir başkası, Konu 1 Adlı "John O" Mallory JO 'yerine 'JM'" baş harfleri' ve yönetici olarak düzenlemek düzeltmek istiyor)

cevap

53

Modeller kesinlikle "kendi" var! Bir model örneğinin bir model örneğine bağlı olarak tanımlanmaya çalıştığını; Bu mümkün değildir, çünkü sınıf ve özniteliklerini tanımlamaktan önce varolamaz (ve olamaz).

, istediğiniz etkiyi elde modeli sınıfının kaydet() yöntemini geçersiz kılmak için. Gerekli örneğe istediğiniz değişiklikleri yapın, ardından gerçek tasarruf için süper sınıfın yöntemini çağırın. İşte hızlı bir örnek.

def save(self, *args, **kwargs): 
    if not self.subject_init: 
     self.subject_init = self.subject_initials() 
    super(Subject, self).save(*args, **kwargs) 

Bu belge, Overriding Model Methods belgelerinde kaplıdır. Django signals kullanma

12

bunu yapmanın daha iyi bir yolu olup olmadığını bilmiyorum, ama yok yapabilirsiniz use a signal handlerthe pre_save signal için:.

from django.db.models.signals import pre_save 

def default_subject(sender, instance, using): 
    if not instance.subject_init: 
     instance.subject_init = instance.subject_initials() 

pre_save.connect(default_subject, sender=Subject) 
+1

'' 'pre_save''' yerine' '' post_save''' ithal ettiniz. – arkocal

+1

@arkocal: Başlıklar için teşekkürler, sadece düzeltildi. Bu gibi durumlarda düzenlemeleri kendiniz önerebilirsiniz, bu gibi şeyleri düzeltmeye yardımcı olur :) –

0

, bu modelden the post_init signal alarak, oldukça erken yapılabilir. o örneğinde paraflanmasıyla çıkarmış kez

from django.db import models 
import django.dispatch 

class LoremIpsum(models.Model): 
    name = models.CharField(
     "Name", 
     max_length=30, 
    ) 
    subject_initials = models.CharField(
     "Subject Initials", 
     max_length=5, 
    ) 

@django.dispatch.receiver(models.signals.post_init, sender=LoremIpsum) 
def set_default_loremipsum_initials(sender, instance, *args, **kwargs): 
    """ 
    Set the default value for `subject_initials` on the `instance`. 

    :param sender: The `LoremIpsum` class that sent the signal. 
    :param instance: The `LoremIpsum` instance that is being 
     initialised. 
    :return: None. 
    """ 
    if not instance.subject_initials: 
     instance.subject_initials = "".join(map(
       (lambda x: x[0] if x else ""), 
       instance.name.split(" "))) 

post_init sinyal sınıfı tarafından gönderilir. Bu şekilde, örnekleme, null olmayan alanlarının ayarlanıp ayarlanmadığını test etmeden önce name için bir değer alır.