Поверхности полей диаграммы 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/