Configuration¶
All configuration is done through class attributes on the viewset. Every option has a sensible default, so none of them are required.
Attribute |
Type |
Default |
Description |
|---|---|---|---|
|
|
|
URL segment used for both endpoints |
|
|
|
Put the field name before the endpoint segment in URLs |
|
|
|
Restrict which fields are exposed ( |
|
|
|
Key name for the choice value in the response |
|
|
|
Key name for the display text in the response |
choices_endpoint_name¶
Default: "choices"
Changes the URL segment for both endpoints. Useful for avoiding conflicts with other custom actions or for matching your API naming conventions.
class TaskViewSet(ChoicesMixin, ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
choices_endpoint_name = "options"
Resulting endpoints:
Before |
After |
|---|---|
|
|
|
|
choices_field_first¶
Default: False
Controls the order of the URL segments for the single-field endpoint. When
set to True, the field name comes before the endpoint name. This can read
more naturally in some APIs.
class TaskViewSet(ChoicesMixin, ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
choices_field_first = True
Resulting endpoints:
Default ( |
Field-first ( |
|---|---|
|
|
|
|
Note
The all-choices endpoint is always just the endpoint name — only the per-field endpoint changes order.
Combining with a custom endpoint name¶
Both options work together:
class TaskViewSet(ChoicesMixin, ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
choices_endpoint_name = "options"
choices_field_first = True
Endpoint |
Description |
|---|---|
|
All choices |
|
Choices for the |
|
Choices for the |
choices_fields¶
Default: None (expose all fields that have choices)
A list of field names to include. Fields not in the list are hidden from both the all-choices endpoint and the per-field endpoint.
class TaskViewSet(ChoicesMixin, ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
choices_fields = ["status"]
GET /tasks/choices/ now returns only status:
{
"status": [
{"value": "active", "display": "Active"},
{"value": "inactive", "display": "Inactive"}
]
}
GET /tasks/choices/priority/ returns 404:
{"detail": "Field 'priority' does not have choices."}
Tip
Use this when your model has many choice fields but you only want to expose a subset through the API.
choices_value_key / choices_display_key¶
Defaults: "value" and "display"
Override the dictionary key names in the response to match what your frontend expects.
class TaskViewSet(ChoicesMixin, ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
choices_value_key = "key"
choices_display_key = "label"
GET /tasks/choices/status/ now returns:
[
{"key": "active", "label": "Active"},
{"key": "inactive", "label": "Inactive"}
]
The all-choices endpoint uses the same keys:
{
"status": [
{"key": "active", "label": "Active"},
{"key": "inactive", "label": "Inactive"}
],
"priority": [
{"key": 1, "label": "Low"},
{"key": 2, "label": "Medium"},
{"key": 3, "label": "High"}
]
}
Full example¶
All options used together:
class TaskViewSet(ChoicesMixin, ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
choices_endpoint_name = "options"
choices_field_first = True
choices_fields = ["status", "priority"]
choices_value_key = "id"
choices_display_key = "text"
Endpoint |
Response |
|---|---|
|
|
|
|
|
404 — |
|
404 — |
Per-viewset configuration¶
Each viewset is configured independently. Different viewsets in the same project can use different settings:
class TaskViewSet(ChoicesMixin, ModelViewSet):
queryset = Task.objects.all()
serializer_class = TaskSerializer
choices_endpoint_name = "options"
class OrderViewSet(ChoicesMixin, ModelViewSet):
queryset = Order.objects.all()
serializer_class = OrderSerializer
choices_endpoint_name = "enums"
choices_value_key = "code"
choices_display_key = "name"
GET /tasks/options/usesvalue/displaykeys.GET /orders/enums/usescode/namekeys.