2010-08-26 15 views
18

¿Cómo puedo hacer que el valor predeterminado para un campo se tome de los objetos existentes de un modelo?Django: valor predeterminado del campo de las instancias del modelo propio

he probado todas estas y no me funcionó:

1)

class ModelA(models.Model): 
    fieldA = models.CharField(default=self.get_previous()) 

    def get_previous(self): 
     return ModelA.objects.all()[0].fieldA 

NameError: name 'self' is not defined

2)

class ModelA(models.Model): 
    fieldA = models.CharField(default=ModelA.get_previous()) 

    @staticmethod 
    def get_previous(): 
     return ModelA.objects.all()[0].fieldA 

NameError: name 'ModelA' is not defined

3)

class ModelA(models.Model): 
    fieldA = models.CharField(default=get_previous()) 

def get_previous(): 
    return ModelA.objects.all()[0].fieldA 

NameError: global name 'get_previous' is not defined

4)

def get_previous(): 
    return ModelA.objects.all()[0].fieldA 

class ModelA(models.Model): 
    fieldA = models.CharField(default=get_previous()) 

NameError: global name 'ModelA' is not defined

que está claro por qué 3) y 4) no funcionará. Me imagino por qué 1) no funcionará - parece que las propiedades de la clase no pueden referirse a las instancias (es decir, a uno mismo). Me imagino por qué 2) no funcionará, aparentemente no hay ninguna referencia a ModelA hasta que el intérprete pase por toda la clase.

Entonces, ¿cómo debo abordar esto?

Respuesta

16

En los ejemplos, debe eliminar el operador de llamada ().

Actualmente, la instrucción se ejecuta inmediatamente en el primer ciclo de lectura-análisis. Al especificar el nombre del símbolo en su lugar, la clase Django recibe un puntero de función que ejecutará cuando realmente necesite el valor predeterminado.

El ejemplo se convierte en:

def get_previous(): 
    return ModelA.objects.all()[0].fieldA 

class ModelA(models.Model): 
    fieldA = models.CharField(default=get_previous) 

Si vas a hacer esto por una gran cantidad de campos, considere la función overridding save, por lo que sólo tiene que buscar el objeto anterior de la base de datos de una sola vez.

+1

¡Buen punto! En mi caso, aunque tengo muchos campos para obtener el valor predeterminado, necesitaría una función separada para cada uno. (Pero consideraré usar lambda para generalizar esto, algo así como 'lambda: get_default ('field_name')') – grucha

+1

Equivalentemente, debería poder hacer 'default = lambda: ModelA.objects.all() [0]. fieldA'. –

+1

Tenga en cuenta que el uso de una función lambda por defecto interferirá con las migraciones ya que las funciones lambda no se pueden serializar. – Ironbeard

3

Si desea simplemente valor por defecto de salida, anular __getattr__() método como este:

class ModelA(models.Model): 
    # your fields 
    def __getattr__(self, name): 
    if(name == 'fieldA' and !self.fieldA): 
     return self.get_previous() 
    else: 
     return super(ModelA, self).__getattr__(name) 

Ahorro valor por defecto de objeto será poco difficultier. La primera solución que me viene a la mente, override save() method (creo que hay una solución más simple)

3

Opción 1: Use model forms. Estas son formas basadas en modelos, que pueden completar fácilmente sus valores con valores de una instancia específica. Esta opción es buena si desea que el valor predeterminado sea algo que se muestre al usuario en formularios, obviamente.

Opción 2: Override the model's save method, y codifique la marca allí - si el campoA es Ninguno, luego ponga algún valor en él. Esta opción es mejor si desea que el valor predeterminado funcione en la capa de datos, y no solo como valores predeterminados (es decir, también para instancias que cree de otras maneras).

+0

Mi objetivo es mostrar el valor predeterminado al usuario, no guardarlo si no hay ningún valor, por lo que la Opción_1 de su respuesta se ve bien. Aunque me gusta más la respuesta de vdboor ya que es un nivel python y no exactamente específico de django. Djangonautas, corrígeme si voy mal ;-) – grucha

Cuestiones relacionadas