Django表单联动:选择Sprint组后显示关联用户选项
需求与解决方案
需求
接触Django仅3个月,现有Sprint 1、Sprint 2等分组,每个分组对应特定用户集合。需要实现:选择某个Sprint分组时,下方自动显示该分组关联的用户选项,供选择。
现有代码
models.py
class Bug(models.Model): name = models.CharField(max_length=200, blank= False, null= False) info = models.TextField() status = models.CharField(max_length=25, choices=status_choice, default="Pending") assign_to = models.ForeignKey(User, on_delete=models.CASCADE, related_name='assigned', blank= True, null= True) assign_sprint = models.ForeignKey(Sprint, on_delete= models.CASCADE) phn_number = PhoneNumberField() uploaded_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete= models.CASCADE, related_name='user_name') created_at = models.DateTimeField(auto_now_add= True) updated_at = models.DateTimeField(blank= True, null = True) updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete= models.CASCADE, related_name='updated_user', null = True, blank=True) screeenshot = models.ImageField(upload_to='pics') platform = models.CharField(max_length=15, choices= platform_choice, default="Web")
forms.py
class BugForm(ModelForm): name = forms.CharField(max_length=200) info = forms.TextInput() status = forms.ChoiceField(choices = status_choice, widget= forms.Select(),initial="Pending", disabled=True) platform = forms.ChoiceField(choices = platform_choice, widget= forms.Select()) phn_number = PhoneNumberField() screeenshot = forms.ImageField() assigned_to = ?? class Meta: model = Bug fields = ['name', 'info','platform' ,'status', 'assign_sprint', 'phn_number', 'screeenshot'] widgets = {'assign_sprint': forms.Select()}
views.py
class BugUpload(LoginRequiredMixin, generic.CreateView): login_url = 'Login' model = Bug form_class = BugForm template_name = 'upload.html' success_url = reverse_lazy('index') def form_valid(self, form): form.instance.uploaded_by = self.request.user inst = form.save(commit=True) message = f"Bug created. Bug id:{inst.bug_id}" messages.add_message(self.request, messages.SUCCESS, message) return super().form_valid(form)
实现步骤
1. 完善Sprint模型(假设未关联用户)
先确保Sprint模型与User建立多对多关联,让每个Sprint可对应多个用户:
# models.py from django.contrib.auth.models import User class Sprint(models.Model): name = models.CharField(max_length=100) users = models.ManyToManyField(User, related_name='sprints') def __str__(self): return self.name
2. 修改forms.py
添加assigned_to字段,初始为空查询集,同时将其加入字段列表:
# forms.py class BugForm(ModelForm): name = forms.CharField(max_length=200) info = forms.Textarea() # 替换原TextInput,适配models中的TextField status = forms.ChoiceField(choices=status_choice, widget=forms.Select(), initial="Pending", disabled=True) platform = forms.ChoiceField(choices=platform_choice, widget=forms.Select()) phn_number = PhoneNumberField() screeenshot = forms.ImageField() assigned_to = forms.ModelChoiceField( queryset=User.objects.none(), required=False, widget=forms.Select() ) class Meta: model = Bug fields = ['name', 'info','platform' ,'status', 'assign_sprint', 'assigned_to', 'phn_number', 'screeenshot'] widgets = {'assign_sprint': forms.Select()} def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 编辑场景下,加载对应Sprint的用户 if 'assign_sprint' in self.data: try: sprint_id = int(self.data.get('assign_sprint')) self.fields['assigned_to'].queryset = Sprint.objects.get(id=sprint_id).users.all() except (ValueError, TypeError, Sprint.DoesNotExist): pass elif self.instance.pk: self.fields['assigned_to'].queryset = self.instance.assign_sprint.users.all()
3. 添加API视图获取Sprint对应用户
在views.py中新增视图,根据Sprint ID返回关联用户列表:
# views.py from django.http import JsonResponse from django.contrib.auth.decorators import login_required @login_required def get_sprint_users(request): sprint_id = request.GET.get('sprint_id') if not sprint_id: return JsonResponse({'users': []}) try: sprint = Sprint.objects.get(id=sprint_id) users = sprint.users.values('id', 'username') return JsonResponse({'users': list(users)}) except Sprint.DoesNotExist: return JsonResponse({'users': []})
在urls.py中添加对应路由:
# urls.py from django.urls import path from . import views urlpatterns = [ # 其他路由... path('get-sprint-users/', views.get_sprint_users, name='get_sprint_users'), ]
4. 修改模板upload.html
添加JS监听Sprint选择事件,动态更新用户选项:
<!-- upload.html --> <form method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form.as_p }} <button type="submit">提交</button> </form> <script> document.addEventListener('DOMContentLoaded', function() { const sprintSelect = document.getElementById('id_assign_sprint'); const userSelect = document.getElementById('id_assigned_to'); // 监听Sprint选择变化 sprintSelect.addEventListener('change', function() { const sprintId = this.value; userSelect.innerHTML = '<option value="">请选择用户</option>'; if (!sprintId) return; // 请求API获取用户列表 fetch(`/get-sprint-users/?sprint_id=${sprintId}`) .then(response => response.json()) .then(data => { data.users.forEach(user => { const option = document.createElement('option'); option.value = user.id; option.textContent = user.username; userSelect.appendChild(option); }); }) .catch(error => console.error('获取用户失败:', error)); }); // 页面加载时若已有Sprint值,触发一次change事件 if (sprintSelect.value) { sprintSelect.dispatchEvent(new Event('change')); } }); </script>
注意事项
- 若Sprint模型已有用户关联逻辑,可调整查询用户的代码
- 确保测试时处于登录状态,API视图添加了登录验证
内容的提问来源于stack exchange,提问作者Jin
相关产品推荐
相关产品推荐

