Повторное использование определений полей Django в других моделях
У меня есть несколько полей в разных моделях. Например,
class A(models.Model):
field_1 = models.CharField(max_length=5, blank=False)
field_2 = models.CharField(max_length=100, blank=False)
field_3 = models.CharField(max_length=200, blank=False)
class B(models.Model):
field_4 = models.CharField(max_length=5, blank=False)
field_5 = models.CharField(max_length=100, blank=False)
field_6 = models.CharField(max_length=200, blank=False)
В дополнение к этим классам я хочу создать класс-лидер. Этот класс содержит данные, которые в будущем будут потенциально скопированы в другие модели. Поэтому ограничения на данные те же, но поскольку это необязательные данные, некоторые могут отсутствовать.
Я хочу использовать DRY, но я также хочу обновить пустое поле. Есть советы, как использовать точные определения полей из этих оригинальных классов?
class Lead(models.Model):
field_1 = A.field_1 # but with updated blank field
field_3 = B.field_3 # but with updated blank field
Я рассматривал зависимость от классов, но в действительности я использую поля из 5 классов, которые, боюсь, превратятся в нечитаемый беспорядок, если ведущий класс будет зависеть от этих полей.
Django ORM
Поскольку Django добавляет слой поверх Python, зависимость классов работает по-другому. Просто ссылаться на определение поля из другого неабстрактного класса и перезаписывать поля не разрешается, так как это сломает базу данных или внесет неприятные ошибки.
Решение
Вместо того, чтобы ссылаться на функцию, скопируйте ее с помощью встроенной функции clone()
.
# Create a new function to gather the field definition from another model
def get_field_from_model(model, field):
return model._meta.get_field(field)
def modify_field(base_model, base_field, **kwargs):
field = get_field_from_model(base_model, base_field)
field_copy = field.clone()
field_copy.__dict__.update(kwargs)
return field_copy
Официально _meta скрытый класс, но он считается стабильным и официальным API. Тем не менее, я поместил его в отдельную функцию для быстрого доступа, если ситуация изменится. Этот подход основан на более подробном ответе здесь (решение похожее, но в исходном вопросе речь шла о копировании полей из переменных, а не в определении класса).
Выполнение
Теперь эта функция может быть использована в определении класса. Она также распознается на этапе миграции и будет создавать новые поля на основе упомянутых полей.
class Lead(models.Model):
field_1 = modify_field(A, 'field_1', blank = True)
field_3 = modify_field(B, 'field_3', blank = True)