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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 09:24:27