Charlestone
Charlestone

Reputation: 1260

How to filter with enum or string and get a same result?

I have a hard time using Enums in Django.

This is my Request model:

class RequestStatuses(Enum):
    new = 'new'
    sent = 'sent'
    done = 'done'


class Request(BaseModel):


    request_number =    models.PositiveIntegerField(default=0)
    type =              models.CharField(max_length=31, blank=True, null=True)

    status =            models.CharField(
        max_length=31,
        choices=[(a.name, a.value) for a in RequestStatuses],
        default=RequestStatuses.new
    )

    sensor =            models.ForeignKey(Sensor, on_delete=models.SET_NULL, blank=True, null=True)
    device =            models.ForeignKey(Device, on_delete=models.SET_NULL, blank=True, null=True)
    user =              models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True)
    payload =           models.TextField(blank=True, null=True)

There is a difference when I create the record with string, or the enum type, which is really annoying...

This works just fine:

    device = Device.objects.create(serial_number=1)
    request = Request(
        device=self.device,
        status=RequestStatuses.sent
    )
    request.save()
    try:
        request = device.request_set.filter(
            status=RequestStatuses.sent
        )[0]
    except IndexError:
        print(device.request_set.all()[0].status)
        pass

But this throws an exception

    device = Device.objects.create(serial_number=1)
    request = Request(
        device=device,
        status='sent'
    )
    request.save()
    try:
        request = device.request_set.filter(
            status=RequestStatuses.sent
        )[0]
    except IndexError:
        print(device.request_set.all()[0].status)
        pass

When I try to filter with status=RequestStatuses.sent.value or just with sent string the first example throws an exception and second works.

What is the point of enums, when you can't filter them by string or vice versa? How can I make it work with api - which will pass string to a filter? Or is it just some cache issue?

Upvotes: 4

Views: 4588

Answers (2)

Zen
Zen

Reputation: 11

In Request model you you need to modify definition of "status"

status = models.CharField(
        max_length=31,
        choices= RequestStatuses.choices(),
        default=RequestStatuses.new.value
    )

Then you may filter following way.

request = Request.objects.filter(status=RequestStatuses.new.name)

Upvotes: 1

Charlestone
Charlestone

Reputation: 1260

I honestly don't know the reason why and whether it is allright to do this, but adding __repr__ and __str__ functions to the enum resolved the issue.

class RequestStatuses(Enum):
    new = 'new'
    sent = 'sent'
    done = 'done'

    def __repr__(self):
        return self.name

    def __str__(self):
        return self.name

Upvotes: 0

Related Questions