2010-04-02 21 views
5

tengo un modelo:¿Cómo hacer que los campos de un modelo de Django se calculen en tiempo de ejecución?

class Person (models.Model): 
    name  = models.CharField() 
    birthday = models.DateField() 
    age  = models.IntegerField() 

Quiero hacer age campo para comportarse como una propiedad:

def get_age (self): 
     return (datetime.datetime.now() - self.birthday).days // 365 

    age = property (get_age) 

pero, al mismo tiempo que necesito age a ser un verdadero campo, por lo que puedo encuéntrelo en Person._meta.fields, y asígnele atributos: age.help_text = "Age of the person", etc.

Obviamente no puedo anular el método Person.save() para calcular y almacenar age en la base de datos, porque inevitablemente se volverá erróneo más adelante (de hecho, no debería almacenarse en la base de datos).

En realidad, no necesito tener setters ahora, pero una buena solución debe tener la función de configuración.

¿Es posible en Django, o probablemente hay un enfoque más pythonic y djangoic a mi problema?

+0

¿Por qué no va a funcionar el método de salvar? –

+0

Porque puede ser incorrecto la próxima vez que obtengamos una instancia de modelo. Este es un ejemplo simple, en realidad tengo campos más complejos, cuyos valores cambian impredecibles, dependiendo de muchos otros factores. –

Respuesta

3

lo estás haciendo de una manera extraña. solo necesita almacenar el cumpleaños (que ya está haciendo).

si necesita realizar consultas según la edad, incorporar la edad y luego buscar los cumpleaños que se ajusten a los requisitos.

from datetime import datetime 

# get people over 50 
age = 50 # in years 
age_ago = datetime.now() - age # use timedelta i don't know the syntax off the top of my head 
Person.objects.filter(birthday__lte=age_ago) # people whose birthday is before fifty years ago 

mismo lo has dicho "[edad] no deben ser almacenados en la base de datos en absoluto"

que tienes razón. no hay ninguna razón para tener el campo de edad ... solo la propiedad estará bien.

+0

Tengo una aplicación automatizada tipo administrador, que usa campos para mostrar y editar información sobre objetos de una manera unificada. Sin la característica que estoy buscando, debo tratar esas propiedades de una manera específica, almacenando y procesando etiquetas (verbose_name), help_texts, etc. por separado. Eso es incómodo y desordenado. –

+0

no debería tener que editar 'edad' solo' cumpleaños'. No importa qué 'cumpleaños' sea 'edad' siempre será una función de 'cumpleaños' (es decir, ahora - cumpleaños). es por eso que no puedo entender lo que estás tratando de decir. –

+0

Tengo una clase: 'clase PersonReportPrinter (ReportPrinter)' con los campos 'model = Person' y' columns = ('id', 'name', 'age') 'y la clase usa' Person._meta.get_field_by_name' para obtener 'verbose_name' y' help_text'.En realidad, la aplicación real es algo más compleja, hay una serie de modelos y varias clases de ayuda, por lo que las soluciones son demasiado molestas. –

0

Creo que la solución es crear un widget personalizado para el campo de cumpleaños. Todo lo que desea es cambiar cómo se muestra el cumpleaños y cómo se edita. que es exactamente el propósito del widget.

lo siento, no tienen el código para eso, pero aquí es un buen punto de partida:

https://docs.djangoproject.com/en/dev/ref/forms/widgets/

1

Otra forma de hacerlo que podría ser más simple, es el uso de formulario personalizado de el modelo de administrador. Algo como esto:

class Person (models.Model): 
    birthday = models.DateField() 

class PersonForm(forms.ModelForm): 
    age = forms.IntegerField() # This will not be in the database 
    class Meta: 
     model = Person 
    def __init__(self, *args, **kwargs): 
     # verify instance was passed 
     instance = kwargs.get('instance') 
     if instance: 
      self.base_fields['age'].initial = (datetime.datetime.now() - self.birthday).days 
     super(PersonForm, self).__init__(*args, **kwargs) 

class FooAdmin(admin.ModelAdmin): 
    form = PersonForm 
    # Save the age in the birthday field 
    def save_model(self, request, obj, form, change): 
     obj.birthday = datetime.datetime.now() + form.cleaned_data['age'] 
     obj.save() 
Cuestiones relacionadas