As mentioned in one of the comments, if you have a limited number of possible choices for a field, Pydantic suggests using Enums
.
In your case this could look like the following (see explanation below):
from enum import Enum, unique
from pydantic import BaseModel
@unique
class BloodGroup(str, Enum):
AB_N_VE = "ab-ve"
AB_P_VE = "ab+ve"
A_N_VE = "a-ve"
A_P_VE = "a+ve"
B_N_VE = "b-ve"
B_P_VE = "b+ve"
O_N_VE = "o-ve"
O_P_VE = "o+ve"
class post(BaseModel):
emp_name: str
bg: BloodGroup
# ...
# omitting other fields to keep it short
p1 = post.parse_obj({"emp_name": "Some Name", "bg": "ab-ve"})
print(p1)
# p1: emp_name='Some Name' bg=<BloodGroup.AB_N_VE: 'ab-ve'>
p2 = post.parse_obj({"emp_name": "Some Name", "bg": BloodGroup.AB_N_VE})
print("p2:", p2)
# p2: emp_name='Some Name' bg=<BloodGroup.AB_N_VE: 'ab-ve'>
p3 = post.parse_obj({"emp_name": "Some Name", "bg": "xyz"})
# Raises exception:
# Traceback (most recent call last):
# File "pydantic_emums.py", line 44, in <module>
# p2 = post.parse_obj({"emp_name": "Some Name", "bg": "xyz"})
# File "pydantic/main.py", line 572, in pydantic.main.BaseModel.parse_obj
# File "pydantic/main.py", line 400, in pydantic.main.BaseModel.__init__
# pydantic.error_wrappers.ValidationError: 1 validation error for post
# bg
# value is not a valid enumeration member; permitted: 'ab-ve', 'ab+ve', 'a-ve', 'a+ve', 'b-ve', 'b+ve', 'o-ve', 'o+ve' (type=type_error.enum; enum_values=[<BloodGroup.AB_N_VE: 'ab-ve'>, <BloodGroup.AB_P_VE: 'ab+ve'>, <BloodGroup.A_N_VE: 'a-ve'>, <BloodGroup.A_P_VE: 'a+ve'>, <BloodGroup.B_N_VE: 'b-ve'>, <BloodGroup.B_P_VE: 'b+ve'>, <BloodGroup.O_N_VE: 'o-ve'>, <BloodGroup.O_P_VE: 'o+ve'>])
The unique
decorator ensures that all values are unique and you don't end up with duplicates by accident (which is what you typically want to avoid).
Since +
and -
are not allowed as variable names in Python, I have used P
(positive) and N
(negative) instead but you could call them whatever you want.
Inheriting from str
in addition to Enum
makes it possible to use comparison operators on the Enum
fields, i.e.:
BloodGroup.A_N_VE == "a-ve"
# True
Keep in mind though, that str
must come before Enum
(see here).
When instantiating the model (post
in your case), you can either use the string representing (p1
) of the blood group or the Enum
field (p2
). Both will result in the same instance.
When anything other than the strings defined by the Enum
class is passed into the model, it will raise a ValidationError
with a detailed description of what is wrong.
Another advantage of using Enum
s like this is that you can import and use them in other modules and parts of your code without having to rely on the string representation. This helps to avoid typos and can give you auto-completion if your editor is configured accordingly.
And if you're writing the results to a database and you're using SQLAlchemy, you can also reuse the same Enums
in the database field definitions.