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

如何在同一Django模板页面中保留两个表单的数据?

Django共用模板时用户资料为空问题修复

问题描述

Django项目中,ProfileUpdateView和UserDeleteView共用profile.html模板。当访问ProfileUpdateView的GET/POST请求时,用户资料数据正常显示;但向UserDeleteView发送POST请求且未勾选accountActivation复选框时,页面虽能渲染,但上方的用户资料区域为空。


相关代码

urls.py

from django.contrib import admin
from django.urls import include, path

from apps.iam.views import ProfileUpdateView, UserDeleteView

urlpatterns = [
    path("accounts/profile", ProfileUpdateView, name="profile_detailupdate"),
    path("accounts/delete", UserDeleteView, name="user_delete"),
]

views.py

import zoneinfo

from django.contrib.auth import get_user_model
from django.contrib.auth import logout as auth_logout
from django.contrib.auth.decorators import login_required
from django.shortcuts import HttpResponseRedirect, get_object_or_404, render
from django.utils import timezone
from django.views.decorators.http import require_http_methods
from django.views.generic import TemplateView, UpdateView

from .forms import ProfileForm
from .models import Profile

User = get_user_model()


# Homepage
class HomeDetailView(TemplateView):
    template_name = "home.html"

# Profile

## Update
@login_required
@require_http_methods(["GET","POST"])
def ProfileUpdateView(request):
    # dictionary for initial data with field names as keys
    context = {}

    # fetch the object related to passed id
    profile_object = get_object_or_404(Profile, id=request.user.id)

    # pass the object as instance in form
    profile_form = ProfileForm(request.POST or None, instance=profile_object)
 
    # save the data from the form
    if profile_form.is_valid():
        profile_form.save()

    # add form dictionary to context
    context["profile_form"] = profile_form

    # activate the new timezone in case changed
    request.session["django_timezone"] = request.user.profile.timezone
    timezone.activate(zoneinfo.ZoneInfo(request.user.profile.timezone))

    return render(request, "profile.html", context)


## Delete
@login_required
@require_http_methods(["POST"])
def UserDeleteView(request):
    # dictionary for initial data with field names as keys
    context = {}

    # fetch the object related to passed id
    user_object = get_object_or_404(Profile, id=request.user.id)

    # pass the object as instance in form
    userdelete_form = ProfileForm(request.POST or None, instance=user_object)

    # add form dictionary to context
    context["userdelete_form"] = userdelete_form

    # user verified account deletion
    if request.POST.get("accountActivation") == "on":
        User = get_user_model()
        user_pk = request.user.pk
        auth_logout(request)
        User.objects.filter(pk=user_pk).delete()
        return render(request, "home.html", context)
    else:
        return render(request, "profile.html", context)

profile.html

{% extends 'base.html' %}
{% load static %}
{% load widget_tweaks %}

{% block head_title %} {{ title }} {% endblock %}

{% block body %}

<div class="container-xxl flex-grow-1 container-p-y">

    <div class="row">
        <div class="col-md-12">

            <div class="card mb-4">
                <h5 class="card-header">Profile Details</h5>
                <!-- Account -->
                <div class="card-body">
                    <div class="d-flex align-items-start align-items-sm-center gap-4">
                        <img src="{% static 'img/avatars/1.png' %}" alt="user-avatar" class="d-block rounded"
                            height="100" width="100" id="uploadedAvatar" />
                        <div class="button-wrapper">
                            <label for="upload" class="btn btn-primary me-2 mb-4" tabindex="0">
                                <span class="d-none d-sm-block">Upload new photo</span>
                                <i class="bx bx-upload d-block d-sm-none"></i>
                                <input type="file" id="upload" class="account-file-input" hidden
                                    accept="image/png, image/jpeg" />
                            </label>
                            <button type="button" class="btn btn-outline-secondary account-image-reset mb-4">
                                <i class="bx bx-reset d-block d-sm-none"></i>
                                <span class="d-none d-sm-block">Reset</span>
                            </button>

                            <p class="text-muted mb-0">Allowed JPG, GIF or PNG. Max size of 800K</p>
                        </div>
                    </div>
                </div>
                <hr class="my-0" />
                <div class="card-body">
                    <form id="formAccountSettings" method="POST" action="{% url 'profile_detailupdate' %}">
                        <!-- Security token by Django -->
                        {% csrf_token %}

                        <!-- form -->
                        {% for hidden in profile_form.hidden_fields %}
                        {{ hidden }}
                        {% endfor %}

                        <div class="row">

                            {% for field in profile_form.visible_fields %}
                            <div class="mb-3 col-md-6">
                                <label for="{{ field.id_for_label }}">{{ field.label }}</label>
                                {% if field.field.widget.input_type == "select" %}
                                {{ field|add_class:'form-control form-select' }}
                                {% else %}
                                {{ field|add_class:'form-control' }}
                                {% endif %}
                                {% for error in field.errors %}
                                <span class="help-block">{{ error }}</span>
                                {% endfor %}
                            </div>
                            {% endfor %}

                            <div class="mt-2">
                                <button name="profile" type="submit" class="btn btn-primary me-2">Save changes</button>
                                <button type="reset" class="btn btn-outline-secondary">Cancel</button>
                            </div>
                    </form>
                </div>
                <!-- /Account -->
            </div>
            <div class="card">
                <h5 class="card-header">Delete Account</h5>
                <div class="card-body">
                    <div class="mb-3 col-12 mb-0">
                        <div class="alert alert-warning">
                            <h6 class="alert-heading fw-bold mb-1">Are you sure you want to delete your account?</h6>
                            <p class="mb-0">Once you delete your account, there is no going back. Please be certain.</p>
                        </div>
                    </div>

                    <form id="formAccountDeactivation" method="POST" action="{% url 'user_delete' %}">
                        <!-- Security token by Django -->
                        {% csrf_token %}

                        <!-- form -->
                        {% for hidden in deleteuser_form.hidden_fields %}
                        {{ hidden }}
                        {% endfor %}

                        <div class="form-check mb-3">
                            <input class="form-check-input" type="checkbox" name="accountActivation"
                                id="accountActivation" />
                            <label class="form-check-label" for="accountActivation">I confirm my account
                                deactivation</label>
                        </div>
                        <button name="delete" type="submit" class="btn btn-danger deactivate-account">Deactivate Account</button>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

{% endblock %}

问题原因

  1. 上下文变量缺失:UserDeleteView返回profile.html时,上下文仅传入了userdelete_form,但模板渲染用户资料区域依赖的是profile_form变量,导致模板无法找到该变量,资料区域为空。
  2. 模板变量名不匹配:模板中删除表单部分使用了deleteuser_form变量,但视图中传入的变量名为userdelete_form,存在拼写差异。

修复方案

1. 修改UserDeleteView,添加profile_form到上下文

更新UserDeleteView函数,在返回profile.html前,创建profile_form并传入上下文,确保模板能渲染用户资料:

@login_required
@require_http_methods(["POST"])
def UserDeleteView(request):
    context = {}

    # 准备profile_form,供模板渲染用户资料区域
    profile_object = get_object_or_404(Profile, id=request.user.id)
    profile_form = ProfileForm(instance=profile_object)
    context["profile_form"] = profile_form

    # 处理删除表单逻辑
    user_object = get_object_or_404(Profile, id=request.user.id)
    userdelete_form = ProfileForm(request.POST or None, instance=user_object)
    context["userdelete_form"] = userdelete_form

    if request.POST.get("accountActivation") == "on":
        User = get_user_model()
        user_pk = request.user.pk
        auth_logout(request)
        User.objects.filter(pk=user_pk).delete()
        return render(request, "home.html", context)
    else:
        return render(request, "profile.html", context)

2. 修正模板中删除表单的变量名

将profile.html中删除表单部分的deleteuser_form改为userdelete_form,匹配视图传入的变量名:

<!-- 修改前 -->
{% for hidden in deleteuser_form.hidden_fields %}
{{ hidden }}
{% endfor %}

<!-- 修改后 -->
{% for hidden in userdelete_form.hidden_fields %}
{{ hidden }}
{% endfor %}

内容的提问来源于stack exchange,提问作者bigredthelogger

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 09:05:27