In Django, you can define a set of choices for any field. If you’re using a SPA frontend, such as React or Vue, then you’ll need to access these choices in a form. Let’s look at two ways to do this.
As an example, we’ll use the following Device
model:
class Device(models.Model):
class Size(models.TextChoices):
SMALL = "S"
MEDIUM = "M"
LARGE = "L"
name = models.CharField(max_length=255)
size = models.CharField(max_length=255, choices=Size.choices)
Hardcode choices in frontend
The fastest approach is to harcode these choices in the frontend.
<select name="size">
<option value="S">Small</option>
<option value="M">Medium</option>
<option value="L">Large</option>
</select>
This breaks the DRY principle, which isn’t ideal. If we want to add a new choice, then we’d have to add it in both the backend and frontend.
Use an API to send choices to frontend
A better approach is to manage these choices only on the backend and pass them around via an API.
Django Rest Framework, the most popular tool for building API’s with Django, makes this very easy using OPTIONS
requests.
Let’s start by building our CRUD endpoints:
# serializers.py
class DeviceSerializer(serializers.ModelSerializer):
class Meta:
model = Device
fields = "__all__"
# views.py
class DeviceViewSet(ModelViewSet):
queryset = Device.objects.all()
serializer_class = DeviceSerializer
# urls.py
router = DefaultRouter()
router.register("devices", DeviceViewSet)
urlpatterns = [path("api/", include(router.urls))]
Now, make an OPTIONS
request to the devices list endpoint. I’m using the httpie cli tool below, which I enjoy more than curl:
// http OPTIONS http://localhost:8000/api/devices/
{
"name": "Device List",
"actions": {
"POST": {
...
"size": {
"choices": [
{"display_name": "Small", "value": "S"},
{"display_name": "Medium", "value": "M"},
{"display_name": "Large", "value": "L"}
],
"label": "Size",
"read_only": false,
"required": true,
"type": "choice"
}
}
},
...
}
See all of our size
choices listed in a clean and strctured format. Our frontend can fetch these choices on page load and dynamically render them.
DRF builds OPTIONS
requests for all endpoints out of the box. It includes the actions
object for POST
and PUT
endpoints (source code). Notice we get the same data for our device instance endpoint:
// http OPTIONS http://localhost:8000/api/devices/1/
{
"name": "Device Instance",
"actions": {
"PUT": {
"size": {
"choices": [
{"display_name": "Small", "value": "S"},
{"display_name": "Medium", "value": "M"},
{"display_name": "Large", "value": "L"}
]
}
}
},
...
}
You can also view these OPTIONS
responses in DRF’s browsable API. Just navigate to the target endpoint and click the blue “OPTIONS” button.
Read more about this feature in DRF’s Metadata documentation.