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

Django问题:点击Follow/Unfollow按钮时出现重复操作异常

问题:CS50W Project4 社交应用关注/取消关注按钮计数异常

我正在完成CS50W的Project4任务,开发一款社交应用,需要在用户个人主页添加Follow(关注)和Unfollow(取消关注)按钮。目前遇到的问题是:点击这两个按钮时,会出现关注数和粉丝数重复增减的异常情况。预期效果是:点击Follow按钮时,自己的关注数(Following)和目标用户的粉丝数(Followers)各增加1。


相关代码

views.py

def seguir(request):
    if request.method == 'POST':
        accion = request.POST.get('accion')
        usuario_accion = request.POST.get('usuario')
        usuario = request.user.username

        # Comprobación de si ya lo esta siguiendo y recuperación de información de usuarios
        perfil_usuario = User.objects.get(username=usuario)
        perfil_usuario_accion = User.objects.get(username=usuario_accion)
        esta_siguiendo = perfil_usuario.seguidos.filter(username=usuario_accion).exists()

        if accion == 'follow':

            # Si no lo esta siguiendo se añade a la lista de seguidos de uno y de seguidores del otro
            if esta_siguiendo == False:
                perfil_usuario_accion.seguidores.add(perfil_usuario)
                perfil_usuario.seguidos.add(perfil_usuario_accion)

            # Redirección a la página del usuario seguido
            return render(request, "network/profile.html", {
                "profile_user": perfil_usuario_accion,
                "logged_user": 0
            })
        
        else:

            # Comprobación de que lo siga
            if esta_siguiendo:
                perfil_usuario.seguidos.remove(perfil_usuario_accion)
                perfil_usuario_accion.seguidores.remove(perfil_usuario)
            
            return render(request, "network/profile.html", {
                "profile_user": perfil_usuario_accion,
                "logged_user": 0
            })

profile.html

{% extends "network/layout.html" %}

{% block body %}
    <h1 id="titulo-perfil">{{ profile_user.username }} profile page</h1>
    <div id="contenedor-seguir">
        <div id="seguidores">Followers: {{ profile_user.seguidores.count }}</div>
        <div id="seguidos">Following: {{ profile_user.seguidos.count }}</div>
    </div>
    {% if logged_user == 0 %}
        <form id="contenedor-botones" action="{% url 'follow' %}" method="post">
            {% csrf_token %}
            <input type="hidden" name="usuario" value="{{ profile_user.username }}">
            <button type="submit" class="btn btn-primary" name="accion" value="follow">Follow</button>
            <button type="submit" class="btn btn-primary", name="accion" value="unfollow">Unfollow</button>
        </form>
    {% endif %}
{% endblock %}

models.py

class User(AbstractUser):
    seguidores = models.ManyToManyField('self', symmetrical='false', related_name='tesiguen', blank=True)
    seguidos = models.ManyToManyField('self', symmetrical='false', related_name='siguiendo', blank=True)

问题根源及修复方案

1. 模型设计冗余,导致重复关联

你的User模型同时定义了seguidores和seguidos两个多对多字段,属于冗余设计。多对多字段的related_name已经可以实现反向关联,不需要单独维护两个字段,手动操作双字段很容易出现关联重复或不一致。

修复models.py:
只保留一个字段维护关注关系,利用反向关联自动获取粉丝列表:

class User(AbstractUser):
    # seguidos 表示当前用户关注的人,反向关联(粉丝)用 followers
    seguidos = models.ManyToManyField('self', symmetrical=False, related_name='followers', blank=True)

此时:

  • user.seguidos.all() → 当前用户关注的人(Following列表)
  • user.followers.all() → 当前用户的粉丝(Followers列表)

2. 视图逻辑冗余+表单重复提交风险

原视图中手动同时操作两个关联字段,加上模型冗余,容易导致重复增减;另外直接render返回页面,浏览器刷新时会重复提交表单,加剧计数异常。

修复views.py:

def seguir(request):
    if request.method == 'POST':
        accion = request.POST.get('accion')
        usuario_accion_username = request.POST.get('usuario')
        try:
            usuario_accion = User.objects.get(username=usuario_accion_username)
        except User.DoesNotExist:
            return redirect('profile', username=usuario_accion_username)
        
        logged_user = request.user
        esta_siguiendo = logged_user.seguidos.filter(pk=usuario_accion.pk).exists()

        if accion == 'follow' and not esta_siguiendo:
            logged_user.seguidos.add(usuario_accion)
        elif accion == 'unfollow' and esta_siguiendo:
            logged_user.seguidos.remove(usuario_accion)
        
        # 重定向代替直接渲染,避免表单重复提交
        return redirect('profile', username=usuario_accion_username)

优化点:

  • 用pk判断关注状态,比username更高效准确
  • 只操作logged_user.seguidos,反向关联的粉丝列表会自动维护
  • 重定向到用户主页,彻底避免刷新重复提交问题

3. 模板按钮逻辑错误

原模板中两个按钮在同一个表单内,无法根据当前关注状态动态显示对应按钮,容易出现误提交操作。

修复profile.html:

{% extends "network/layout.html" %}

{% block body %}
    <h1 id="titulo-perfil">{{ profile_user.username }} profile page</h1>
    <div id="contenedor-seguir">
        <div id="seguidores">Followers: {{ profile_user.followers.count }}</div>
        <div id="seguidos">Following: {{ profile_user.seguidos.count }}</div>
    </div>
    {% if request.user.is_authenticated and request.user != profile_user %}
        <form id="contenedor-botones" action="{% url 'follow' %}" method="post">
            {% csrf_token %}
            <input type="hidden" name="usuario" value="{{ profile_user.username }}">
            {% if request.user.seguidos.filter(pk=profile_user.pk).exists %}
                <button type="submit" class="btn btn-primary" name="accion" value="unfollow">Unfollow</button>
            {% else %}
                <button type="submit" class="btn btn-primary" name="accion" value="follow">Follow</button>
            {% endif %}
        </form>
    {% endif %}
{% endblock %}

改进点:

  • 仅当登录用户不是目标用户本人时,才显示操作按钮
  • 根据当前关注状态动态显示对应按钮,避免误操作
  • 直接使用request.user判断状态,无需传递额外变量

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 00:44:50