Как сделать поля модели Django рассчитанными во время выполнения? - PullRequest
6 голосов
/ 02 апреля 2010

У меня есть модель:

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

Я хочу сделать age поле, которое будет вести себя как свойство:

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

    age = property (get_age)

, но в то же время мне нужно ageбыть истинным полем, поэтому я могу найти его в Person._meta.fields и присвоить ему атрибуты: age.help_text = "Age of the person" и т. д.

Очевидно, я не могу просто переопределить Person.save() метод для вычисления и хранения ageв базе данных, потому что это неизбежно впоследствии станет неправильным (на самом деле, его вообще не следует хранить в базе данных).

На самом деле, мне сейчас не нужны сеттеры, но хорошее решениедолжен иметь функцию настройки.

Возможно ли это в Django, или, возможно, есть более питонический и djangoic подход к моей проблеме?

Ответы [ 4 ]

3 голосов
/ 02 апреля 2010

вы идете об этом странным образом. вам нужно только сохранить день рождения (что вы уже делаете).

если вам нужно выполнить запросы в зависимости от возраста, укажите возраст, а затем выполните поиск по дням рождения, которые соответствуют требованиям.

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

Вы сами сказали: «[возраст] вообще не должен храниться в базе данных»

ты прав. нет никаких причин, чтобы иметь поле возраста ... просто свойство будет хорошо.

1 голос
/ 05 сентября 2012

Еще один способ, который может быть проще, - это использование пользовательской формы в модели администратора. Примерно так:

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()
0 голосов
/ 29 апреля 2019

Этого можно добиться с помощью django-computed-property .

Сначала вы должны установить pip django-computed-property с помощью следующей команды:

pip install django-computed-property

Затем вы добавляете computed_property в список INSTALLED_APPS в settings.py :

INSTALLED_APPS = [
    ...
    'computed_property'
]

Теперь вы можете импортировать и использовать включенные классы полей в своих моделях следующим образом:

from django.db import models
from computed_property import ComputedTextField

import random


class Person(models.Model):
    age = ComputedTextField(compute_from='calculation')

    @property
    def calculation(self):
        return str(random.randint(1,101))

Поле возраста в модели Person возвращает случайное число каждый раз, когда оно вызывается, чтобы продемонстрировать, что оно рассчитывается во время выполнения.

Вы можете читать значения из поля возраста как обычно, но вы не можете установить значение поля. Когда к полю обращаются и когда модель экземпляр сохранен, он вычислит значение поля, используя при условии вызова (функция / лямбда), свойство age или атрибут age

0 голосов
/ 05 сентября 2012

Я думаю, что решение состоит в том, чтобы создать собственный виджет для поля дня рождения. Все, что вам нужно, это изменить способ отображения дня рождения и способ его редактирования. это как раз и есть цель виджета.

Извините, у меня нет кода для этого, но вот хорошее место для начала:

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

...