Django如何从Session取值并设置到表单HiddenInput?
问题描述
我开发了一个Django应用,需要从Session中获取值并放入HiddenInput组件中。
我的视图中有如下代码:
@login_required(redirect_field_name='login') def obra_open_view(request, obra_id): obra = get_object_or_404(Obra, pk=obra_id) if obra: request.session['obra_aberta_id'] = obra.id request.session['obra_aberta_name'] = obra.nome return redirect('obra_detail_url') else: request.session['obra_aberta_id'] = 0 request.session['obra_aberta_name'] = "" return redirect('obra_lista_url')
当obra_aberta_id存在值时,我尝试将该值放入HiddenInput中:
class FormCarga(ModelForm): class Meta: model = Carga fields = ('__all__') widgets = { 'tag': forms.TextInput(attrs={'class': 'form-control'}), 'nome': forms.TextInput(attrs={'class': 'form-control'}), 'descricao': forms.Textarea(attrs={'class': 'form-control'}), 'potencia': forms.TextInput(attrs={'class': 'form-control'}), 'unidade_medida_potencia': forms.Select(attrs={'class': 'form-control'}), 'area': forms.Select(attrs={'class': 'form-control'}), 'tensao': forms.Select(attrs={'class': 'form-control'}), 'fonte': forms.Select(attrs={'class': 'form-control'}), 'atividade': forms.Select(attrs={'class': 'form-control'}), 'fator_potencia': forms.Select(attrs={'class': 'form-control'}), 'condutores_carregados': forms.Select(attrs={'class': 'form-control'}), 'obra': forms.HiddenInput(attrs={'class': 'form-control','initial' : request.session['obra_aberta_id']}), }
但遇到错误:name 'request' is not defined
请问如何从Session中获取值并设置到这个HiddenInput中?
附相关模型代码:
class Carga(models.Model): tag = models.CharField(max_length=10) nome = models.CharField(max_length=100) descricao = models.TextField(blank=True, verbose_name='Descrição') potencia = models.CharField(blank=True, max_length=10, verbose_name='Potência') unidade_medida_potencia = models.ForeignKey(UnidadeMedidaPotencia, on_delete=models.DO_NOTHING, null=True, blank=True, verbose_name='Unidade de Medida') area = models.ForeignKey(Area, on_delete=models.DO_NOTHING, null=True, verbose_name='Área') tensao = models.ForeignKey(Tensao, on_delete=models.DO_NOTHING, null=True, verbose_name='Tensão') fonte = models.ForeignKey(Fonte, on_delete=models.DO_NOTHING, null=True) atividade = models.ForeignKey(Atividade, on_delete=models.DO_NOTHING, null=True) fator_potencia = models.ForeignKey(FatorPotencia, on_delete=models.DO_NOTHING, null=True, verbose_name='Fator de Potência') condutores_carregados = models.ForeignKey(CondutoresCarregados, on_delete=models.DO_NOTHING, null=True) obra = models.ForeignKey(Obra, on_delete=models.DO_NOTHING, null=False) class Obra(models.Model): nome = models.CharField(max_length=255) descricao = models.TextField(blank=True, verbose_name='Descrição') # opcional cnpj = models.CharField(max_length=15, blank=True) revisao = models.CharField(max_length=10, blank=True, verbose_name='Revisão') # opcional descricao_revisao = models.TextField(blank=True, verbose_name='Descrição da Revisão') bloqueado = models.BooleanField(default=False) # Se o externo for apagado, não apaga a obra cliente = models.ForeignKey(PessoaJuridica, on_delete=models.DO_NOTHING, null=True) participantes = models.ManyToManyField(PessoaFisica, through='FuncaoPessoaObra') contato = models.ManyToManyField(Contato) # (equivalente ao tostring) aparecer o nome no site admin def __str__(self): return self.nome
补充模板代码:
{% extends 'base.html' %} {% block titulo %} {{ nome_pagina }} {% endblock %} {% block conteudo %} {% include 'parciais/_messages.html' %} <h1 class="mt-3 mb-3"> {{ nome_pagina }} </h1> <form method="post"> {% csrf_token %} {{ form.as_p }} {% if editavel %} <button type="submit" class="btn btn-primary float-right">Salvar</button> {% else %} <a class="btn btn-primary float-right" href="{% url url_lista %}">Lista</a> {% endif %} </form> </br> {% endblock %}
以及使用表单的视图代码:
@login_required(redirect_field_name='login') def carga_new_view(request): if request.method == 'POST': form = FormCarga(request.POST) if form.is_valid(): form.save() messages.success(request, 'Carga cadastrada com sucesso!') # Redirect para a lista de cargas return redirect('carga_list_url') else: form = FormCarga() nome_pagina = 'Nova Carga' page_dictionary = { 'form': form, 'nome_pagina': nome_pagina, 'editavel': True, 'url_lista': 'carga_list_url', } return render(request, 'item.html', page_dictionary)
解决方案
你遇到的问题核心是:表单类定义阶段无法直接访问request对象,request仅存在于视图函数的上下文环境中。以下是两种可行的解决方法:
方法一:在视图中传递初始值
修改carga_new_view视图,在实例化表单时通过initial参数传入Session中的值:
@login_required(redirect_field_name='login') def carga_new_view(request): if request.method == 'POST': form = FormCarga(request.POST) if form.is_valid(): form.save() messages.success(request, 'Carga cadastrada com sucesso!') return redirect('carga_list_url') else: # 从Session获取obra_aberta_id,默认值设为0避免验证失败 initial_data = { 'obra': request.session.get('obra_aberta_id', 0) } form = FormCarga(initial=initial_data) nome_pagina = 'Nova Carga' page_dictionary = { 'form': form, 'nome_pagina': nome_pagina, 'editavel': True, 'url_lista': 'carga_list_url', } return render(request, 'item.html', page_dictionary)
同时修改表单类,移除widgets里的initial属性:
class FormCarga(ModelForm): class Meta: model = Carga fields = '__all__' # 修正原代码的元组写法错误 widgets = { 'tag': forms.TextInput(attrs={'class': 'form-control'}), 'nome': forms.TextInput(attrs={'class': 'form-control'}), 'descricao': forms.Textarea(attrs={'class': 'form-control'}), 'potencia': forms.TextInput(attrs={'class': 'form-control'}), 'unidade_medida_potencia': forms.Select(attrs={'class': 'form-control'}), 'area': forms.Select(attrs={'class': 'form-control'}), 'tensao': forms.Select(attrs={'class': 'form-control'}), 'fonte': forms.Select(attrs={'class': 'form-control'}), 'atividade': forms.Select(attrs={'class': 'form-control'}), 'fator_potencia': forms.Select(attrs={'class': 'form-control'}), 'condutores_carregados': forms.Select(attrs={'class': 'form-control'}), 'obra': forms.HiddenInput(attrs={'class': 'form-control'}), }
方法二:重写表单的__init__方法
如果需要在表单内部处理逻辑,可以重写表单的__init__方法,接收request参数并设置初始值:
class FormCarga(ModelForm): def __init__(self, *args, **kwargs): # 从kwargs中取出request,无值时设为None self.request = kwargs.pop('request', None) super().__init__(*args, **kwargs) # 若request存在且Session中有有效值,设置字段初始值 if self.request and 'obra_aberta_id' in self.request.session: self.fields['obra'].initial = self.request.session['obra_aberta_id'] class Meta: model = Carga fields = '__all__' widgets = { # 其他widgets保持不变 'obra': forms.HiddenInput(attrs={'class': 'form-control'}), }
然后在视图中实例化表单时传入request参数:
# GET请求场景 form = FormCarga(request=request) # POST请求场景 form = FormCarga(request.POST, request=request)
注意事项
- 由于
Carga模型中obra字段是null=False,需确保Session中obra_aberta_id存在有效值,或设置合理默认值,避免表单验证失败。 - 原代码中
fields = ('__all__')是不规范写法,会被解析为字符串而非元组,建议改为fields = '__all__'或fields = ('__all__',)。
内容的提问来源于stack exchange,提问作者rohrigme
相关产品推荐
相关产品推荐

