1

So I'm trying to simulate a flags field in Django (4.0 and Python3) the same way I could do in C or C++. It would look like this:

typedef enum{
    flagA = 0,
    flagB,
    flagC
} myFlags;

Having a uint8 that by default is 00000000 and then depending on if the flags are on or off I'd do some bitwise operations to turn the three least significant bits to 1 or 0.

Now, I could do that in my model by simply declaring a PositiveSmallIntegerField or BinaryField and just creating some helper functions to manage all this logic.

Note that I DO NOT NEED to be able to query by this field. I just want to be able to store it in the DB and very occasionally modify it.

Since it's possible to extend the Fields, I was wondering if it would be cleaner to encapsulate all this logic inside a custom Field inheriting from BinaryField. But I'm not really sure how can I manipulate the Field value from my custom class.

class CustomBinaryField(models.BinaryField):
    description = "whatever"

    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = 1
        super().__init__(*args, **kwargs)

For instance, if I wanted to create a method inside CustomBinaryField, like the following, where the myFlagsStr contains a str representation of the enum.

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

Not sure how to get the actual value stored in the DB to make this if comparisons.

Maybe mine is not the best approach to handle this, so I'm open to any suggestions you guys might have. But I think I could manage to do this the way I'm doing if I knew how to get the actual binary value from the DB from my functions.

I have seen there is a library https://github.com/disqus/django-bitfield that handles this but it limits to using only PostgreSQL and also, as mentioned before, I don't really need to filter by these flags, so something more simpler will do too.

lpares12
  • 3,504
  • 4
  • 24
  • 45

1 Answers1

1

Well, in django common approach for building such functionalities is using MultipleChoiceField. It presumes that data is stored in the related table, which, I believe, is not very what you want.

The second opportunity is to use ArrayField which also isn't suitable for you since you don't want your solution to be limited to PostgreSQL.

If you're going to do this quickly and straightforward, you might use JSONField and store the string or numeric IDs of your Choices. But if you are accustomed to C++, you're not gonna like it this way :)

JSONField is supported on MariaDB 10.2.7+, MySQL 5.7.8+, Oracle, PostgreSQL, and SQLite (with the JSON1 extension enabled).

If so, you should look at SmallIntegerField, it's stored as 16-bit signed int and use getter-setter approach to maintain it, like this. The idea of implementation of the methods you suggested is right in general.

Good luck :)

Yevgeniy Kosmak
  • 3,561
  • 2
  • 10
  • 26
  • I think I will go for the SmallIntegerField approach, thanks for the info. Anyways, I'm a bit curious about how to get the value of the Field when creating a CustomField that inherits from, for example, the IntegerField. In the case I wanted to create a function inside the custom Field class I mean. Any ideas on how to do that too? – lpares12 Dec 23 '21 at 07:50
  • I'm not completely sure, official docs about `CustomField` look quite intuitive and descriptive for me. Isn't [that](https://docs.djangoproject.com/en/4.0/howto/custom-model-fields/#converting-values-to-python-objects) what you need exactly about it? – Yevgeniy Kosmak Dec 23 '21 at 12:39
  • One more idea for you. You can use [Flag enum](https://docs.python.org/3/library/enum.html#intflag) in implementation. – Yevgeniy Kosmak Dec 27 '21 at 02:00