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 подход для его обслуживания, подобно этому. Идея реализации предложенных Вами методов в целом правильная.

Удачи :)

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