Home > Back-end >  Limit the choices of a choice field in the model class
Limit the choices of a choice field in the model class

Time:08-18

This SO answer shows how to limit a choice field in the form. However, I have a choice field with options that should never be shown to the user. Hence, I want to limit the choice field options in the model class to adhere to the DRY principle and to prevent myself from forgetting to adding code in future forms.

Here is a simple example:

UNIT_TYPES = Choices(
    (1, 'APARTMENT', 'Apartment'),
    (2, 'TOWNHOUSE', 'Townhouse'),
    (3, 'SINGLE_FAMILY', 'Single-family home'),
    (4, 'OTHER', 'Other') # Never show in any views
)

For this particular example, only the first three choices should be shown to the user in forms whereas the fourth will only be set on the backend if certain conditions are met.

Any idea how to achieve this?

CodePudding user response:

Using a custom manager which will always exclude one of your choices :

APARTMENT = 1
TOWNHOUSE = 2
SINGLE_FAMILY = 3
OTHER = 4
UNIT_TYPES = (
    (APARTMENT, 'Apartment'),
    (TOWNHOUSE, 'Townhouse'),
    (SINGLE_FAMILY, 'Single-family home'),
    (OTHER, 'Other')
)


class CustomManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().exclude(unit_type=OTHER)


class Model(models.Model):
    unit_type = models.IntegerField(
        choices=UNIT_TYPES,
        validators=[MinValueValidator(APARTMENT), MaxValueValidator(OTHER)]
    )

    objects = CustomManager()

CodePudding user response:

I would create another set of choices within your models.py file for those that are hidden, e.g.

UNIT_TYPES = Choices(
    (1, 'APARTMENT', 'Apartment'),
    (2, 'TOWNHOUSE', 'Townhouse'),
    (3, 'SINGLE_FAMILY', 'Single-family home'),
)

HIDDEN_TYPES = Choices(
    (4, 'OTHER', 'Other') # Never show in any views
)

You should be able to set the model choices as UNIT_TYPES HIDDEN_TYPES and then access HIDDEN_TYPES within your form file. With reference to the answer you linked, you can customised the __init__() function to set the choices based on UNIT_TYPES and ignore HIDDEN_TYPES completely.

If there are any other places within your application that a user might see these choices, then you will need to take care to exclude the hidden types. As far as I'm aware, there isn't a way of making this more dynamic - the model __init__() method doesn't have access to the request object which you would tell you which user is involved.

  • Related