Когда создается Django Model, могу ли я определить поля в __init__?
Набираются ли они ниже одинаково?
Первый код, определяющий поля в разделе атрибутов класса, рекомендуется документами django
class Musician(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
Второй код, который я хочу использовать, определяет поля в функции init.
class Musician(models.Model):
def __init__(self, *args, **kwargs):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
instrument = models.CharField(max_length=100)
super().__init__(*args, **kwargs)
Я хочу использовать вторые коды, когда я определяю classmethod в Model для определения функций, проверяющих поля, как показано ниже.
class HyperLinks(model.Model):
def __init__(self, *args, **kwargs):
self.links = models.JSONField(default=[], validators=[self.validate_links])
super().__init__(*args, **kwargs)
@staticmethod
def validate_links(data):
pass
Второй код в моем вопросе не работает.
Я нашел похожие вопросы, Хранение переменных в классе Python, Инициализация/декларация атрибутов в классе Python: где их разместить?
Согласно вышеприведенным вопросам, атрибуты класса не могут быть совместно использованы __dict__
функцией.
class A(object):
foo = None
class B(object):
def __init__(self):
self.foo = None
A.__dict__
# result
# mappingproxy({'__module__': '__main__', 'foo': None, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None})
B.__dict__
# result
# mappingproxy({'__module__': '__main__', '__init__': <function B.__init__ at 0x110805790>, '__dict__': <attribute '__dict__' of 'B' objects>, '__weakref__': <attribute '__weakref__' of 'B' objects>, '__doc__': None})
Есть различия, которые библиотека django называет моделями. Поэтому, когда мы определяем модели, мы должны избегать определения атрибутов в функциях __init__
. Это приводит к неожиданным ошибкам.
В частности, в django Migration Section, django не может распознать поля, тогда он не будет создавать колонки или удалять ваши колонки. А в objects.create(), имена колонок.
Тогда, как насчет объявления функции перед присвоением атрибутов поля, как показано ниже?
class HyperLinks(models.Model):
@staticmethod
def validate_links(data):
"""
example
links = [("github", "https://github.com/yeop-sang"), ("homepage", "http://yeop.kr")]
"""
if type(data) is not list:
raise ValidationError(
'links should be list'
)
for datum in data:
if type(datum) is not tuple:
raise ValidationError(
'links should be list contained tuple'
)
if len(datum) is not 2:
raise ValidationError(
'link should be contain type and link'
)
if not (type(datum[0]) is str and type(datum[1]) is str):
raise ValidationError(
'link and type should be string'
)
links = models.JSONField(default=[], validators=[validate_links])
Существует исключение TypeError: 'staticmethod' object is not callable
.
(Ссылка).
Чтобы исправить это, я могу изменить последнюю строку как links = models.JSONField(default=[], validators=[validate_links.__get__(object)])
В конечном счете, для валидации полей лучше всего создавать функции, отделенные от класса Model, что рекомендуется в документации django и @0sVoid.