如何让Django下拉表单仅展示当前用户所属条目而非全部用户的条目?
解决方案
核心原因
Django ModelForm的外键字段默认会加载对应模型的全量数据作为下拉选项,你没有手动修改该字段的查询集,所以所有用户的Workout都会展示在下拉菜单中。
1. 修改 forms.py 代码
给RoutineForm增加初始化方法,接收当前登录用户参数,过滤workout字段的可选范围:
class RoutineForm(forms.ModelForm): """creates a form for a routine""" class Meta: model = Routine fields = ['workout'] labels = {'workout': 'Workout'} def __init__(self, *args, **kwargs): # 取出传入的当前用户参数 user = kwargs.pop('user', None) super().__init__(*args, **kwargs) if user: # 仅保留当前用户创建的Workout作为可选选项 self.fields['workout'].queryset = Workout.objects.filter(owner=user).order_by('text')
2. 修改 views.py 代码
实例化表单时传入当前登录用户,同时补全Routine实例的所有者绑定逻辑:
from django.shortcuts import render, redirect from django.http import HttpResponseRedirect, Http404 from django.urls import reverse from django.contrib.auth.decorators import login_required @login_required def routine(request): """display a dropdown of all workouts for a user""" if request.method != 'POST': # GET请求实例化表单时传入当前用户 form = RoutineForm(user=request.user) else: # POST请求实例化表单也需要传入用户,保证校验逻辑正常 form = RoutineForm(data=request.POST, user=request.user) if form.is_valid(): new_routine = form.save(commit=False) # 给新生成的Routine绑定当前用户为所有者 new_routine.owner = request.user new_routine.save() return redirect('index') # 原代码中workouts变量未定义,不需要的话可以直接删除 context = {'form':form} return render(request, 'routine_workouts_app/routine.html', context)
额外说明
上述修改同时自带安全校验:即使用户恶意修改前端提交不属于自己的Workout ID,表单在校验时会匹配你设置的过滤后的查询集,不符合的ID会直接校验失败,不会产生越权数据。
内容的提问来源于stack exchange,提问作者Kyle F.
相关产品推荐
相关产品推荐

