Поверхности полей диаграммы Django

есть ли что-то вроде getters и seters для полей модели django?

Например, у меня есть текстовое поле, в котором мне нужно заменить строку перед ее сохранением (в панели администратора, как для операций вставки, так и для обновления) и сделать другую, другую заменять каждый раз при чтении. Эти замены строк являются динамическими и должны выполняться в момент сохранения и чтения.

Поскольку я использую python 2.5, я не могу использовать python 2.6 getters/setters.

Любая помощь?

Ответы

Ответ 1

Вы также можете переопределить setattr и getattr. Например, предположим, что вы хотите пометить поле грязное, у вас может быть что-то вроде этого:

class MyModel:
    _name_dirty = False

    name = models.TextField()

    def __setattr__(self, attrname, val):
        super(MyModel, self).__setattr__(attrname, val)

        self._name_dirty = (attrname == 'name')


    def __getattr__(self, attrname):
        if attrname == 'name' and self._name_dirty:
            raise('You should get a clean copy or save this object.')

        return super(MyModel, self).__getattr__(attrname)

Ответ 2

Вы можете добавить pre_save обработчик сигналов в модель, которую вы хотите сохранить, которая обновляет значения до их сохранения в базе данных.

Это не совсем то же самое, что и функция setter, поскольку значения остаются в их некорректном формате до тех пор, пока значение не будет сохранено. Если это приемлемый компромисс для вашей ситуации, тогда сигналы - это самый простой способ достичь этого, не работая вокруг Django ORM.

Edit: В вашей ситуации стандартные свойства Python - это, вероятно, путь к этому. Там долго стоящий билет, чтобы добавить надлежащую поддержку getter/setter в Django, но это не простая проблема для решения.

Вы можете добавить поля свойств в админ, используя методы в этот пост в блоге

Ответ 3

Переопределение setattr является хорошим решением, за исключением того, что это может вызвать проблемы с инициализацией объекта ORM из БД. Тем не менее, есть трюк, чтобы обойти это, и он универсален.

class MyModel(models.Model):
    foo = models.CharField(max_length = 20)
    bar = models.CharField(max_length = 20)

    def __setattr__(self, attrname, val):
        setter_func = 'setter_' + attrname
        if attrname in self.__dict__ and callable(getattr(self, setter_func, None)):
            super(MyModel, self).__setattr__(attrname, getattr(self, setter_func)(val))
        else:
            super(MyModel, self).__setattr__(attrname, val)

    def setter_foo(self, val):
        return val.upper()

Секрет " attrname in self.__ dict __". Когда модель инициализируется либо новой, либо гидратированной из __ dict __!

Ответ 4

Пока я исследовал проблему, я нашел решение с помощью декоратора property.

Например, если у вас есть

class MyClass(models.Model):
    my_date = models.DateField()

вы можете превратить его в

class MyClass(models.Model):
    _my_date = models.DateField(
        db_column="my_date",  # allows to avoid migrating to a different column
    )

    @property
    def my_date(self):
        return self._my_date

    @my_date.setter
    def my_date(self, value):
        if value > datetime.date.today():
            logger.warning("The date chosen was in the future.")
        self._my_date = value

и избегайте любых миграций.

Источник: https://www.stavros.io/posts/how-replace-django-model-field-property/