Когда создается 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.

Вернуться на верх