Какой способ объединения нескольких столбцов базы данных в одно поле модели является наиболее подходящим для Django?

Я несколько раз сталкивался с необходимостью иметь поле модели Django, которое включает в себя несколько столбцов базы данных, и мне интересно, какой способ сделать это наиболее подходящий для Django.

На ум приходят три варианта использования.

  1. Я хочу предоставить поле, которое обертывает другое поле, сохраняя информацию о том, было ли обернутое поле установлено или нет. Примером использования этого конкретного поля может быть динамическая конфигурация. Вводится новое значение конфигурации, и представление отмечает себя как зависимое от значения конфигурации, перенаправляя, если значение не установлено. Хранение того, установлено ли оно еще или нет, позволяет легко кэшировать состояние на неопределенный срок. Это также позволяет самому значению конфигурации быть не нулевым, и приложение может игнорировать любое значение, которое оно может иметь, когда не установлено.

  2. Я хочу предоставить денежное поле, которое объединяет десятичное (или целочисленное) значение и валюту.

  3. Я хочу предоставить поле файла со ссылкой на некое правило доступа, определяющее, должен ли запрос включать его/запрос на него быть успешным.

Для каждого из вариантов использования существует обходной путь, который в каждом случае кажется менее элегантным.

  1. Определите поля конфигурации как nullable. Это нежелательно по нескольким причинам: это устраняет валидность NULL как значения для самой конфигурации, поэтому тристаты и другие случаи использования NULL должны стать парой полей или другим типом данных, или крайним случаем; null=True на полях позволяет им быть установленными обратно в None в модельформ и админке без написания пользовательского FormField для них каждый раз; и каждый столбец с нулевым значением в базе данных, вероятно, плохой дизайн.

  2. Определите поле как подкласс DecimalField с аргументом, принимающим строку, и используйте его для внесения другого поля в модель. (Это то, что делает django-money). Опять же, это нежелательно: поля появляются в модели "как по волшебству", а настройка поля валюты становится неочевидной.

  3. Вместо этого определите комбинированное поле файл+правило как целую модель, и один-к-одному к ней из модели, где вы хотите иметь поле. Это решение подходит для всех случаев использования, но опять же имеет свои недостатки: для каждого экземпляра поля требуется дополнительный JOIN - можно представить User с profile_picture, cv, passport, private_key и т.д. ; существует неявное требование .select_related(*fields) в каждом запросе, который когда-либо захочет получить доступ к этим полям; а в схеме связанной модели холодные данные будут перемежаться с горячими данными повсюду, учитывая, что они используются повсеместно. Также могут быть соображения, когда речь идет о

В дополнение к решению 3., есть также возможность определить фабрику mixin, которая создает несколько полей с подходящими именами и любыми желаемыми свойствами и методами. Опять же, это не идеально, потому что в итоге пользователь получает поля, определенные в теле модели, а также выше в списке наследования.

Я думаю, что основная причина, по которой я продолжаю ходить по кругу, заключается в том, что пользовательские поля модели Django всегда определяются в терминах одного базового поля, потому что это делается путем наследования.

Каков общепринятый способ достижения этой цели?

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