2010-12-07 12 views
55

Tengo un modelo que me gustaría incluir el nombre de un sujeto y sus iniciales. (Los datos son un tanto anónima y rastreado por las iniciales.)Campo Django modelo predeterminado basado en otro campo en el mismo modelo

En este momento, escribí

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) 

Como se indica en la última línea, yo preferiría ser capaz de tener las iniciales en realidad se almacenan en el base de datos como un campo (independiente del nombre), pero que se inicializa con un valor predeterminado basado en el campo de nombre. Sin embargo, tengo problemas ya que los modelos django no parecen tener un "yo".

Si cambio la línea a subject_init = models.CharField("Subject initials", max_length=2, default=subject_initials), puedo hacer el syncdb, pero no puedo crear nuevos sujetos.

¿Esto es posible en django, teniendo una función invocable dar un valor predeterminado a un campo basado en el valor de otro campo?

(Para los curiosos, la razón por la que quiero separar las iniciales de mi tienda por separado es en casos raros donde los apellidos extraños pueden ser diferentes a los que estoy rastreando. Por ejemplo, alguien más decidió que el sujeto 1 llamado "John O" Mallory" son las iniciales 'JM' en lugar de 'JO' y quiere arreglar editarlo como administrador)

Respuesta

53

¡Los modelos ciertamente tienen un "yo"! Es solo que estás tratando de definir un atributo de una clase de modelo como dependiente de una instancia modelo; eso no es posible, ya que la instancia no (y no puede) existir antes de definir la clase y sus atributos.

Para obtener el efecto que desea, anule el método save() de la clase de modelo. Haga los cambios que desee a la instancia necesaria, luego llame al método de la superclase para hacer el ahorro real. Aquí hay un ejemplo rápido.

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

Esto se cubre en Overriding Model Methods en la documentación.

12

no sé si hay una mejor manera de hacer esto, pero se puede use a signal handler para the pre_save signal:.

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

Has importado '' 'post_save''' en lugar de' 'pre_save'''. – arkocal

+1

@arkocal: gracias por el aviso, solo lo corrigieron. Puede sugerir ediciones usted mismo en tales casos, ayuda a arreglar cosas como esta :) –

0

Usando Django signals, esto puede hacerse bastante temprano, recibiendo the post_init signal del modelo.

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

La señal post_init es enviado por la clase una vez que se ha hecho de inicialización en la instancia. De esta forma, la instancia obtiene un valor para name antes de probar si sus campos no anulables están configurados.

Cuestiones relacionadas