Повторное использование определений полей 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)
Вернуться на верх