You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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代码,无需处理。

修改步骤

  1. 删除实例化代码:去掉View中form = DonneeForm(boitier=boitier.pk)这一行。
  2. 用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 00:21:26