Django 从 0 到 1 打造完整电商平台:个人中心与用户信息修改

IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我也会在其它平台持续发布最新文章,助你少走弯路。

大家好,我是IT策士。用户登录之后,第一件想做的事往往是看看自己的账号信息,或者改个昵称、换个密码。今天我们就来打造电商平台的 个人中心------让用户有一个属于自己的"小窝",并且能自助修改手机号、邮箱、密码等信息。

本篇的内容会大量复用之前注册模块里的邮箱激活逻辑,同时引入 login_required 装饰器来保护敏感页面。跟着我一步步来,你会发现 Django 处理这些用户操作是多么顺手。


一、需求分析

个人中心需要实现以下功能:

  • 展示基本信息:用户名、手机号、邮箱、邮箱激活状态。

  • 修改基本信息:允许用户更换用户名、手机号、邮箱。

  • 修改邮箱后 ,邮箱激活状态重置为 False,并重新发送激活邮件。

  • 修改手机号时,需要通过短信验证码验证新手机号(暂用模拟)。

  • 修改密码:旧密码验证通过后才能设置新密码。

  • 权限控制:仅登录用户可访问,且只能修改自己的信息。


二、定义表单

apps/users/forms.py 中追加两个表单。

2.1 个人信息表单

bash 复制代码
class UpdateProfileForm(forms.ModelForm):
    class Meta:
        model = User
        fields = ['username', 'phone', 'email']
        widgets = {
            'username': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': '用户名'
            }),
            'phone': forms.TextInput(attrs={
                'class': 'form-control',
                'placeholder': '手机号'
            }),
            'email': forms.EmailInput(attrs={
                'class': 'form-control',
                'placeholder': '邮箱'
            }),
        }

    def clean_phone(self):
        phone = self.cleaned_data.get('phone')
        if phone:
            # 排除当前用户,检查手机号是否被其他人占用
            if User.objects.filter(phone=phone).exclude(pk=self.instance.pk).exists():
                raise forms.ValidationError('该手机号已被其他用户绑定')
        return phone

    def clean_email(self):
        email = self.cleaned_data.get('email')
        if email:
            if User.objects.filter(email=email).exclude(pk=self.instance.pk).exists():
                raise forms.ValidationError('该邮箱已被其他用户绑定')
        return email

这里使用 ModelForm 直接绑定用户模型,简化字段定义。

2.2 修改密码表单

bash 复制代码
class ChangePasswordForm(forms.Form):
    old_password = forms.CharField(
        label='当前密码',
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': '请输入当前密码'
        })
    )
    new_password = forms.CharField(
        label='新密码',
        min_length=6,
        max_length=20,
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': '新密码(至少6位)'
        })
    )
    confirm_password = forms.CharField(
        label='确认新密码',
        widget=forms.PasswordInput(attrs={
            'class': 'form-control',
            'placeholder': '再次输入新密码'
        })
    )

    def clean(self):
        cleaned_data = super().clean()
        new = cleaned_data.get('new_password')
        confirm = cleaned_data.get('confirm_password')
        if new and confirm and new != confirm:
            raise forms.ValidationError('两次新密码不一致')
        return cleaned_data

三、编写视图

打开 apps/users/views.py,在原有基础上增加以下内容。

先确保导入齐全,顶部加入:

bash 复制代码
from django.contrib.auth.decorators import login_required
from django.contrib.auth import update_session_auth_hash
from .forms import UpdateProfileForm, ChangePasswordForm
import random
from django.core.mail import send_mail

3.1 个人中心主页

bash 复制代码
@login_required(login_url='users:login')
def personal_center(request):
    return render(request, 'users/center.html')

这个视图极为简单,只是渲染模板。模板里会直接使用 {``{ user }} 显示当前登录用户的信息。

3.2 修改个人信息

bash 复制代码
@login_required(login_url='users:login')
def update_profile(request):
    user = request.user

    if request.method == 'POST':
        form = UpdateProfileForm(request.POST, instance=user)
        if form.is_valid():
            old_email = user.email
            form.save()

            # 如果邮箱发生了变更,重置激活状态并发送激活邮件
            new_email = form.cleaned_data.get('email')
            if new_email and new_email != old_email:
                user.email_active = False
                user.save(update_fields=['email_active'])

                # 生成激活 token
                token = str(random.randint(100000, 999999))
                request.session[f'email_token_{user.id}'] = token
                activate_url = request.build_absolute_uri(
                    f'/users/activate/{user.id}/{token}/'
                )
                send_mail(
                    subject='重新激活你的电商账号',
                    message=f'你的邮箱已更新,请点击链接重新激活:{activate_url}',
                    from_email='noreply@example.com',
                    recipient_list=[new_email],
                )
                messages.warning(request, '邮箱已更新,请前往新邮箱查收激活邮件(终端查看)。')
            else:
                messages.success(request, '个人信息更新成功。')
            return redirect('users:center')
    else:
        form = UpdateProfileForm(instance=user)

    return render(request, 'users/update_profile.html', {'form': form})

说明:

  • 使用 instance=user 绑定当前用户,ModelForm 自动完成保存。

  • 如果修改了邮箱,程序会自动重置 email_active 并发送激活邮件。激活链接沿用第 6 篇的 activate_email 视图,完全复用。

3.3 修改密码

bash 复制代码
@login_required(login_url='users:login')
def change_password(request):
    if request.method == 'POST':
        form = ChangePasswordForm(request.POST)
        if form.is_valid():
            user = request.user
            old = form.cleaned_data['old_password']

            # 校验旧密码是否正确
            if not user.check_password(old):
                form.add_error('old_password', '当前密码不正确')
                return render(request, 'users/change_password.html', {'form': form})

            # 设置新密码并保存
            user.set_password(form.cleaned_data['new_password'])
            user.save()

            # 更新 session 认证哈希,防止密码修改后 session 失效
            update_session_auth_hash(request, user)

            messages.success(request, '密码修改成功。')
            return redirect('users:center')
    else:
        form = ChangePasswordForm()

    return render(request, 'users/change_password.html', {'form': form})

关键点update_session_auth_hash 的作用是,在修改密码后让当前用户的 session 继续保持有效,否则 Django 会立即将该用户登出。这一行必不可少。

3.4 短信验证码发送(复用)

我们在第 6 篇已经写了 send_sms_code 视图,个人中心修改手机号时也可以调用它。由于前端 AJAX 请求需要 CSRF 令牌,我们会在模板中直接复用它。


四、配置 URL

apps/users/urls.py 中添加新路由:

bash 复制代码
urlpatterns = [
    # ... 之前的路由 ...
    path('center/', views.personal_center, name='center'),
    path('update/', views.update_profile, name='update_profile'),
    path('change_password/', views.change_password, name='change_password'),
]

五、设计模板

5.1 个人中心主页

创建 apps/users/templates/users/center.html

bash 复制代码
{% extends 'base.html' %}
{% block title %}个人中心{% endblock %}

{% block content %}
<div class="row">
    <!-- 侧边栏 -->
    <div class="col-md-3">
        <div class="card shadow-sm">
            <div class="card-header bg-primary text-white">
                <h5 class="mb-0">个人中心</h5>
            </div>
            <ul class="list-group list-group-flush">
                <li class="list-group-item active">
                    <a href="{% url 'users:center' %}" class="text-white text-decoration-none">个人信息</a>
                </li>
                <li class="list-group-item">
                    <a href="{% url 'users:update_profile' %}" class="text-decoration-none">修改资料</a>
                </li>
                <li class="list-group-item">
                    <a href="{% url 'users:change_password' %}" class="text-decoration-none">修改密码</a>
                </li>
                <li class="list-group-item">
                    <a href="#" class="text-decoration-none">收货地址</a>
                </li>
                <li class="list-group-item">
                    <a href="#" class="text-decoration-none">我的订单</a>
                </li>
            </ul>
        </div>
    </div>

    <!-- 主内容 -->
    <div class="col-md-9">
        <div class="card shadow-sm">
            <div class="card-header bg-light">
                <h4 class="mb-0">👤 基本信息</h4>
            </div>
            <div class="card-body">
                <table class="table table-bordered">
                    <tr><th style="width:150px;">用户名</th><td>{{ user.username }}</td></tr>
                    <tr><th>手机号</th><td>{{ user.phone|default:"未绑定" }}</td></tr>
                    <tr><th>邮箱</th><td>{{ user.email|default:"未绑定" }}</td></tr>
                    <tr>
                        <th>邮箱状态</th>
                        <td>
                            {% if user.email_active %}
                                <span class="badge bg-success">已激活</span>
                            {% else %}
                                <span class="badge bg-warning text-dark">未激活</span>
                            {% endif %}
                        </td>
                    </tr>
                    <tr><th>注册时间</th><td>{{ user.date_joined|date:"Y-m-d H:i" }}</td></tr>
                </table>
            </div>
        </div>
    </div>
</div>
{% endblock %}

5.2 修改个人信息页面

创建 apps/users/templates/users/update_profile.html

bash 复制代码
{% extends 'base.html' %}
{% block title %}修改资料{% endblock %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-6">
        <div class="card shadow-sm">
            <div class="card-body p-4">
                <h3 class="text-center mb-4">✏️ 修改个人资料</h3>

                <form method="post" novalidate>
                    {% csrf_token %}

                    <div class="mb-3">
                        <label class="form-label">用户名</label>
                        {{ form.username }}
                        {{ form.username.errors }}
                    </div>

                    <div class="mb-3">
                        <label class="form-label">手机号</label>
                        {{ form.phone }}
                        {{ form.phone.errors }}
                    </div>

                    <div class="mb-3">
                        <label class="form-label">邮箱</label>
                        {{ form.email }}
                        {{ form.email.errors }}
                    </div>

                    {% if form.non_field_errors %}
                        <div class="alert alert-danger">{{ form.non_field_errors.0 }}</div>
                    {% endif %}

                    <button type="submit" class="btn btn-primary w-100">保存修改</button>
                    <a href="{% url 'users:center' %}" class="btn btn-outline-secondary w-100 mt-2">取消</a>
                </form>
            </div>
        </div>
    </div>
</div>
{% endblock %}

5.3 修改密码页面

创建 apps/users/templates/users/change_password.html

bash 复制代码
{% extends 'base.html' %}
{% block title %}修改密码{% endblock %}

{% block content %}
<div class="row justify-content-center">
    <div class="col-md-6">
        <div class="card shadow-sm">
            <div class="card-body p-4">
                <h3 class="text-center mb-4">🔒 修改密码</h3>

                <form method="post" novalidate>
                    {% csrf_token %}

                    <div class="mb-3">
                        <label class="form-label">{{ form.old_password.label }}</label>
                        {{ form.old_password }}
                        {{ form.old_password.errors }}
                    </div>

                    <div class="mb-3">
                        <label class="form-label">{{ form.new_password.label }}</label>
                        {{ form.new_password }}
                        {{ form.new_password.errors }}
                    </div>

                    <div class="mb-3">
                        <label class="form-label">{{ form.confirm_password.label }}</label>
                        {{ form.confirm_password }}
                        {{ form.confirm_password.errors }}
                    </div>

                    {% if form.non_field_errors %}
                        <div class="alert alert-danger">{{ form.non_field_errors.0 }}</div>
                    {% endif %}

                    <button type="submit" class="btn btn-danger w-100">修改密码</button>
                    <a href="{% url 'users:center' %}" class="btn btn-outline-secondary w-100 mt-2">取消</a>
                </form>
            </div>
        </div>
    </div>
</div>
{% endblock %}

六、更新导航栏

确保 templates/base.html 的导航栏中,"个人中心"链接指向 {% url 'users:center' %}

bash 复制代码
<li><a class="dropdown-item" href="{% url 'users:center' %}">个人中心</a></li>

七、完整流程测试

启动服务器:

bash 复制代码
python manage.py runserver

7.1 访问个人中心

  1. 以任一用户登录,例如 13800138000

  2. 点击导航栏的用户名 → "个人中心"。

  3. 浏览器显示用户名、手机号、邮箱及激活状态、注册时间。

7.2 修改用户名

  1. 在个人中心页面点击侧边栏"修改资料"(或直接访问 /users/update/)。

  2. 将用户名改为新名字,点击"保存修改"。

  3. 页面重定向回个人中心,提示"个人信息更新成功。",用户名已更新。

终端输出:

bash 复制代码
[21/May/2026 14:30:22] "POST /users/update/ HTTP/1.1" 302 0
[21/May/2026 14:30:22] "GET /users/center/ HTTP/1.1" 200 3654

7.3 修改邮箱并重新激活

  1. 在修改资料页,将邮箱改为 newemail@example.com

  2. 提交后,页面提示"邮箱已更新,请前往新邮箱查收激活邮件(终端查看)。"

  3. 终端控制台打印激活邮件:

bash 复制代码
Content-Type: text/plain; charset="utf-8"
Subject: 重新激活你的电商账号
From: noreply@example.com
To: newemail@example.com

你的邮箱已更新,请点击链接重新激活:http://127.0.0.1:8000/users/activate/2/835472/
  1. 复制链接在浏览器打开,提示"邮箱激活成功!",个人中心中邮箱状态变为"已激活"。

控制台记录:

bash 复制代码
[21/May/2026 14:35:10] "POST /users/update/ HTTP/1.1" 302 0
...
MIME-Version: 1.0
...
[21/May/2026 14:35:10] "GET /users/center/ HTTP/1.1" 200 3654
[21/May/2026 14:37:02] "GET /users/activate/2/835472/ HTTP/1.1" 302 0

7.4 修改密码

  1. 在个人中心侧边栏点击"修改密码"。

  2. 输入当前密码、新密码(如 newpass123)、确认新密码,提交。

  3. 提示"密码修改成功。",并保持在登录状态(不会掉线)。

  4. 退出后重新登录,旧密码失效,新密码生效。

验证旧密码错误的情况:

  • 故意输错当前密码,提交后页面显示"当前密码不正确"。

终端输出:

bash 复制代码
[21/May/2026 14:40:33] "POST /users/change_password/ HTTP/1.1" 200 2987

八、总结与下集预告

今天我们完成了用户体系的核心闭环:

  • 搭建了个人中心展示页面,带侧边栏导航;

  • 实现了个人信息修改,修改邮箱自动触发重新激活;

  • 实现了安全的密码修改流程,确保旧密码校验和 session 保持;

  • 所有视图都加上 login_required 保护,未登录用户自动跳转登录页。

有了牢固的用户身份与个人资料管理基础,明天我们要进入一个更贴近电商场景的功能------收货地址管理。用户下单前必须选择地址,所以第 9 篇我们将实现地址的增删改查,并支持设置默认地址。

想了解更多还可以去其它平台搜索「IT策士」,一起升级 IT 思维 !


本文为《Django 从 0 到 1 打造完整电商平台》系列第 8 篇,作者:IT策士,未经授权禁止转载。

相关推荐
小明同学014 小时前
C++后端项目:统一大模型接入 SDK(五)
服务器·c++·后端·计算机网络·语言模型
SimonKing4 小时前
IP定位库的完美替代品:ip2region,开源、免费!
java·后端·程序员
XiYang-DING4 小时前
【Spring】Lombok
java·后端·spring
ZC跨境爬虫4 小时前
模块化烹饪小程序开发日记 Day5:(后端Flask接口开发与AI智能解析菜谱的实现)
前端·人工智能·后端·python·ui·flask
Yeats_Liao4 小时前
物联网接入层技术剖析(一):从select到epoll
java·linux·后端·物联网·struts
财经资讯数据_灵砚智能4 小时前
基于全球经济类多源新闻的NLP情感分析与数据可视化(日间)2026年5月21日
大数据·人工智能·python·信息可视化·自然语言处理
小钻风33664 小时前
Spring Boot WebSocket 两种集成方式深度解析
spring boot·后端·websocket
IT_陈寒4 小时前
Vite热更新失效?我在这坑里卡了一下午
前端·人工智能·后端
Artech4 小时前
[对比学习LangChain和MAF-03]完全不同的Agent设计哲学
python·ai·langchain·c#·agent·maf