Django视图向表单传参报错:formset_factory使用异常
问题
尝试在Django中从View向Form传递变量,当前传参方法能生效,但调用DonneeForm(boitier=boitier.pk)时会返回完整HTML代码。希望既能实现变量传递,又能让DonneeForm保持类的使用方式(直接传入类给formset_factory,而非实例,但直接传类无法传参)。
相关代码
Form.py
class DonneeForm(forms.ModelForm): def __init__(self, *args, **kwargs): self.boitier = kwargs.pop("boitier", 1) # 从views.py传递的参数 super().__init__(*args, **kwargs) boitier = get_object_or_404(Boitier, pk=int(self.boitier)) self.fields['connexion_donnee'].queryset = boitier.donnee class Meta: model = Donnee fields = ['utilise', 'connexion_donnee', 'nom', 'type_donnee', 'valeur_min', 'valeur_max', 'tolerance', 'afficher_valeur', 'inverse'] labels = {} widgets = { 'type_donnee': forms.Select(attrs={"readonly": "True"}) }
View.py
type_capteur = get_object_or_404(TypeCapteur, pk=pk) capteur = get_object_or_404(Capteur, pk=article) type_capteur_donnees = type_capteur.donnee.all().count() print(DonneeForm(boitier=boitier.pk)) form = DonneeForm(boitier=boitier.pk) donnee_form_set = formset_factory(form, extra=type_capteur_donnees, max_num=type_capteur_donnees, absolute_max=type_capteur_donnees) formset_donnee = donnee_form_set if request.method == 'POST': formset = donnee_form_set(request.POST, request.FILES) if formset.is_valid(): for form in formset: if form.cleaned_data: donnee = form.save(commit=False) donnee.capteur = capteur donnee.save() capteur.save() return redirect("smart_workshop_app:configuration_capteurs") else: initial = [] for type_donnee in type_capteur.donnee.all(): initial.append({'type_donnee': type_donnee, 'nom': type_donnee.nom}) formset = formset_donnee(initial=initial) print(formset_donnee) context = {"formset": formset, "instance_id": pk, "instance_article": article} return render(request, 'smart_workshop_app/ajouter_donnees_capteur.html', context)
报错信息
<tr> <th><label for="id_utilise">Donnée utilisée :</label></th> <td> <input type="checkbox" name="utilise" id="id_utilise"> </td> </tr> <tr> <th><label for="id_connexion_donnee">Connexion donnee :</label></th> <td> <select name="connexion_donnee" id="id_connexion_donnee"> <option value="" selected>---------</option> <option value="1">Capt_Distance_Dist_0</option> [...]</td> </tr>
内部服务器错误: /fr/ajouter_donnees_capteur/4/28 Traceback (most recent call last): File "C:\Users\regac\anaconda3\envs\smart_workshop\lib\site-packages\asgiref\sync.py", line 472, in thread_handler raise exc_info[1] File "C:\Users\regac\anaconda3\envs\smart_workshop\lib\site-packages\django\core\handlers\exception.py", line 38, in inner response = await get_response(request) File "C:\Users\regac\anaconda3\envs\smart_workshop\lib\site-packages\django\core\handlers\base.py", line 233, in _get_response_async response = await wrapped_callback(request, *callback_args, **callback_kwargs) File "C:\Users\regac\anaconda3\envs\smart_workshop\lib\site-packages\asgiref\sync.py", line 435, in __call__ ret = await asyncio.wait_for(future, timeout=None) File "C:\Users\regac\anaconda3\envs\smart_workshop\lib\asyncio\tasks.py", line 408, in wait_for return await fut File "C:\Users\regac\anaconda3\envs\smart_workshop\lib\site-packages\asgiref\current_thread_executor.py", line 22, in run result = self.fn(*self.args, **self.kwargs) File "C:\Users\regac\anaconda3\envs\smart_workshop\lib\site-packages\asgiref\sync.py", line 476, in thread_handler return func(*args, **kwargs) File "C:\Users\regac\anaconda3\envs\smart_workshop\lib\site-packages\django\contrib\auth\decorators.py", line 21, in _wrapped_view return view_func(request, *args, **kwargs) File "C:\Users\regac\anaconda3\envs\smart_workshop\lib\site-packages\django\utils\decorators.py", line 130, in _wrapped_view response = view_func(request, *args, **kwargs) File "C:\Users\regac\PycharmProjects\djangoProject\smart_workshop\smart_workshop_app\views.py", line 268, in ajouter_donnees_capteur donnee_form_set = formset_factory(form, extra=type_capteur_donnees, max_num=type_capteur_donnees, File "C:\Users\regac\anaconda3\envs\smart_workshop\lib\site-packages\django\forms\formsets.py", line 495, in formset_factory return type(form.__name__ + 'FormSet', (formset,), attrs) AttributeError: 'DonneeForm' object has no attribute '__name__' HTTP GET /fr/ajouter_donnees_capteur/4/28?boitier=2 500 [0.26, 127.0.0.1:51847] C:\Users\regac\PycharmProjects\djangoProject\smart_workshop\smart_workshop_app\views.py changed, reloading.
解决方案
核心问题
报错原因是formset_factory需要传入表单类而非表单实例,你当前传入的form = DonneeForm(boitier=boitier.pk)是已经实例化的对象,所以会触发AttributeError。而打印表单实例返回HTML是Django的正常行为——表单实例转字符串时会渲染成HTML代码,无需处理。
修改步骤
- 删除实例化代码:去掉View中
form = DonneeForm(boitier=boitier.pk)这一行。 - 用
form_kwargs传递参数:调用formset_factory时,直接传入DonneeForm类,并通过form_kwargs参数把boitier传递给每个表单实例。
修改后的View关键代码:
type_capteur = get_object_or_404(TypeCapteur, pk=pk) capteur = get_object_or_404(Capteur, pk=article) type_capteur_donnees = type_capteur.donnee.all().count() # 直接传入DonneeForm类,通过form_kwargs传递参数 donnee_form_set = formset_factory(DonneeForm, extra=type_capteur_donnees, max_num=type_capteur_donnees, absolute_max=type_capteur_donnees, form_kwargs={'boitier': boitier.pk}) formset_donnee = donnee_form_set # POST和GET逻辑保持不变 if request.method == 'POST': formset = donnee_form_set(request.POST, request.FILES) # ... 后续代码不变 else: initial = [] for type_donnee in type_capteur.donnee.all(): initial.append({'type_donnee': type_donnee, 'nom': type_donnee.nom}) formset = formset_donnee(initial=initial) # ... 后续代码不变
原理说明
form_kwargs是formset_factory的内置参数,它会把字典中的键值对作为关键字参数,传递给每个表单实例的__init__方法。这样既满足了formset_factory对表单类的要求,又能把boitier参数传递给每个表单实例,实现你需要的功能。
内容的提问来源于stack exchange,提问作者RomainR
相关产品推荐
相关产品推荐

