Django: имитация флагового поля с помощью BInaryField
Итак, я пытаюсь смоделировать поле флагов в Django (4.0 и Python3) так же, как это можно сделать на C или C++. Это выглядело бы следующим образом:
typedef enum{
flagA = 0,
flagB,
flagC
} myFlags;
Имея uint8
, который по умолчанию равен 00000000
, а затем в зависимости от того, включены или выключены флаги, я бы сделал несколько побитовых операций, чтобы обратить три наименее значимых бита в 1 или 0.
Теперь я могу сделать это в своей модели, просто объявив PositiveSmallIntegerField
или BinaryField
и просто создав несколько вспомогательных функций для управления всей этой логикой.
Обратите внимание, что мне НЕ НУЖНО иметь возможность делать запросы по этому полю. Я просто хочу иметь возможность хранить его в БД и очень иногда изменять его.
Поскольку есть возможность расширять Fields, я подумал, не будет ли чище инкапсулировать всю эту логику внутри пользовательского Field, наследующего от BinaryField. Но я не совсем понимаю, как я могу манипулировать значением поля из моего пользовательского класса.
class CustomBinaryField(models.BinaryField):
description = "whatever"
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 1
super().__init__(*args, **kwargs)
Например, если бы я хотел создать метод внутри CustomBinaryField
, подобный следующему, где myFlagsStr
содержит строковое представление перечисления.
def getActiveFlags(self):
// For each bit which is set to 1 in the Binary value
// add it to an array with it's name such as: [flagA, flagC]
array = []
if self.value & (1 << myFlags.flagA):
array.append(myFlagsStr[flagA])
if self.value & (1 << myFlags.flagB):
array.append(myFlagsStr[flagB])
if self.value & (1 << myFlags.flagC):
array.append(myFlagsStr[flagC])
return array
Не уверен, как получить фактическое значение, хранящееся в БД, чтобы сделать это if
сравнение.
Возможно, мой подход не самый лучший, поэтому я открыт для любых ваших предложений. Но я думаю, что мне удалось бы сделать это так, как я делаю, если бы я знал, как получить фактическое двоичное значение из БД из моих функций.
Я видел, что есть библиотека https://github.com/disqus/django-bitfield, которая обрабатывает это, но она ограничивается использованием только PostgreSQL, а также, как упоминалось ранее, мне не очень нужно фильтровать по этим флагам, поэтому подойдет и что-то более простое.
Ну, в django распространенным подходом для построения таких функций является использование MultipleChoiceField
. Он предполагает, что данные хранятся в связанной таблице, что, как мне кажется, не совсем то, что вам нужно.
Вторая возможность - использовать ArrayField
, что также не подходит вам, поскольку вы не хотите, чтобы ваше решение было ограничено PostgreSQL.
Если вы собираетесь сделать это быстро и просто, вы можете использовать JSONField
и хранить строковые или числовые идентификаторы ваших Choices
. Но если вы привыкли к C++, вам такой способ не понравится :)
JSONField поддерживается в MariaDB 10.2.7+, MySQL 5.7.8+, Oracle, PostgreSQL и SQLite (с включенным расширением JSON1).
.
Если да, то вам следует посмотреть на SmallIntegerField
, он хранится как 16-битный знаковый int и использовать getter-setter
подход для его обслуживания, подобно этому. Идея реализации предложенных Вами методов в целом правильная.
Удачи :)