2010-04-02 2 views
5

J'ai un modèle:Comment faire pour qu'un champ de modèle Django soit calculé lors de l'exécution?

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

Je veux faire le terrain age à se comporter comme une propriété:

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

    age = property (get_age) 

mais en même temps, je dois age être un vrai champ, donc je peux trouvez-le dans Person._meta.fields, et attribuez-lui des attributs: age.help_text = "Age of the person", etc.

De toute évidence, je ne peux pas simplement remplacer la méthode Person.save() pour calculer et stocker age dans la base de données, car il se produira inévitablement mal plus tard (en fait, il ne devrait pas être stocké dans la base de données du tout).

En fait, je n'ai pas besoin de setters maintenant, mais une bonne solution doit avoir une fonction de réglage.

Est-il possible dans Django, ou probablement il y a une approche plus pythonique et djangoic à mon problème?

+0

Pourquoi se redéfinissant la méthode de sauvegarde fonctionne pas? –

+0

Parce que cela peut être faux la prochaine fois que nous obtenons une instance de modèle. C'est un exemple simple, j'ai en réalité des champs plus complexes, dont les valeurs changent de façon imprévisible, étant dépendantes de plusieurs autres facteurs. –

Répondre

3

vous allez à ce sujet d'une manière étrange. vous avez seulement besoin de stocker l'anniversaire (que vous faites déjà).

Si vous avez besoin de faire des requêtes en fonction de l'âge, prenez en compte l'âge, puis effectuez une recherche sur les anniversaires correspondant aux exigences.

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 

vous avez dit vous-même « [l'âge] ne doivent pas être stockés dans la base de données du tout »

vous avez raison. il n'y a aucune raison d'avoir le champ d'âge ... juste la propriété ira bien.

+0

J'ai une application de type admin, qui utilise des champs pour afficher et éditer des informations sur les objets d'une manière unifiée. Sans la fonctionnalité que je recherche, je dois traiter ces propriétés d'une manière spécifique, stocker et traiter les étiquettes (verbose_name), help_texts, etc. séparément. C'est maladroit et désordonné. –

+0

vous ne devriez pas avoir à modifier 'age' que' 'birthday''. Peu importe ce que «anniversaire» est «l'âge» sera toujours une fonction de «anniversaire» (c'est-à-dire maintenant - anniversaire). C'est pourquoi je ne peux pas comprendre ce que vous essayez de dire. –

+0

J'ai une classe: 'class PersonReportPrinter (ReportPrinter)' avec les champs 'model = Person' et' columns = ('id', 'name', 'age') 'et la classe utilise' Person._meta.get_field_by_name' pour obtenez 'verbose_name' et' help_text'.En fait, l'application réelle est un peu plus complexe, il y a un certain nombre de modèles et plusieurs classes d'aide, donc les solutions de contournement sont trop ennuyeuses. –

0

Je pense que la solution est de créer un widget personnalisé pour le champ anniversaire. Tout ce que vous voulez, c'est changer la façon dont l'anniversaire est affiché et comment il est édité. c'est exactement le but du widget.

Désolé je n'ai pas le code pour cela, mais voici un bon endroit pour commencer:

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

1

Une autre façon d'aller à ce qui pourrait être plus simple, est d'utiliser le formulaire personnalisé dans le modèle d'administration. Quelque chose comme ceci:

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() 
Questions connexes