ViewSet中SlugField无法在JSON自动表单渲染下拉选项的解决方法
Got it, let's sort out that form rendering issue you're facing. The problem is that DRF's auto-generated browsable API doesn't default to a dropdown for SlugRelatedField—it uses a plain text input instead. But we can tweak your serializer to keep your existing API behavior intact while making the form show a proper dropdown of department names.
Solution: Update the CourseSerializer
Modify your CourseSerializer to explicitly tell DRF to use a select widget for the department field:
from django import forms from rest_framework import serializers import your_app.models as models # Adjust this import to match your app's structure class CourseSerializer(serializers.ModelSerializer): department = serializers.SlugRelatedField( many=False, read_only=False, slug_field='name', queryset=models.Department.objects.all(), # Add this form_field configuration to enable the dropdown form_field=forms.ModelChoiceField( queryset=models.Department.objects.all(), to_field_name='name', label='Department' ) ) class Meta: model = models.Course fields = ( 'id', 'course_name', 'department', 'course_number', 'credits' )
What this does:
- The
form_fieldparameter overrides DRF's default text input for this field, replacing it with aModelChoiceFieldthat renders as a dropdown. to_field_name='name'ensures the form submits the department's name (matching yourSlugRelatedField'sslug_field), so your existing POST request logic works exactly as before—no changes needed to your viewset or API behavior.- The dropdown automatically populates with all existing Department names from your database, and will update dynamically if you add new departments later.
Alternative Approach (DRF-Native)
If you'd rather avoid importing Django forms directly, you can override the serializer's get_fields method to adjust the widget only for the browsable API:
from django import forms from rest_framework import serializers from rest_framework.renderers import HTMLFormRenderer import your_app.models as models class CourseSerializer(serializers.ModelSerializer): department = serializers.SlugRelatedField( many=False, read_only=False, slug_field='name', queryset=models.Department.objects.all() ) def get_fields(self): fields = super().get_fields() # Only adjust the widget if we're rendering the HTML form if self.context.get('request') and HTMLFormRenderer.format in self.context['request'].accepted_renderer.format: fields['department'].widget = forms.Select(choices=[(dept.name, dept.name) for dept in models.Department.objects.all()]) return fields class Meta: model = models.Course fields = ( 'id', 'course_name', 'department', 'course_number', 'credits' )
This checks if we're rendering for the browsable API's HTML form and swaps the widget to a dropdown only in that scenario, leaving your API's JSON response and programmatic POST behavior completely unchanged.
内容的提问来源于stack exchange,提问作者Justin Dearing

