如何在Django中为匿名用户实现基于IP的点赞点踩按钮
用IP地址替代用户实现Django点赞点踩功能
问题背景
我正在开发一个Django网站,为了吸引更多访客,决定不做用户登录/登出功能。现在需要实现点赞点踩按钮,但要把原本用request.user标识用户的逻辑换成用IP地址,请问该怎么改?以下是我目前基于request.user实现的代码:
原视图代码(views.py,Dislike逻辑类似)
@login_required(login_url="login") def Like(request, slug): add = Add.objects.get(slug=slug) # 点赞时取消点踩 is_dislike = False for dislike in add.dislikes.all(): if dislike == request.user: is_dislike = True break if is_dislike: add.dislikes.remove(request.user) # 处理点赞逻辑 is_like = False for like in add.likes.all(): if like == request.user: is_like = True break if not is_like: add.likes.add(request.user) if is_like: add.likes.remove(request.user) next = request.POST.get("next", "/") return HttpResponseRedirect(next)
原模板代码(review.html)
<div class="rate-added-rule"> <form action="{% url 'like' added_data.slug %}" method="POST"> {% csrf_token %} <input type="hidden" name="next" value="{{ request.path }}"> <button type="submit" class="like-button"> <i class="far fa-thumbs-up">LIKE<span>VOTES: {{ added_data.likes.all.count }}</span></i> </button> </form> <form action="{% url 'dislike' added_data.slug %}" method="POST"> {% csrf_token %} <input type="hidden" name="next" value="{{ request.path }}"> <button type="submit" class="dislike-button"> <i class="far fa-thumbs-down">DISLIKE<span>VOTES: {{ added_data.dislikes.all.count }}</span></i> </button> </form> </div>
解决方案
1. 修改模型结构
原来的likes和dislikes是关联User的多对多字段,现在换成基于IP的投票记录,推荐新建一个Vote模型统一管理投票:
# models.py from django.db import models class Add(models.Model): # 保留你原有的字段,比如slug、内容等 slug = models.SlugField(unique=True) # 移除原来的likes和dislikes字段 class Vote(models.Model): LIKE = 1 DISLIKE = -1 VOTE_CHOICES = [ (LIKE, 'Like'), (DISLIKE, 'Dislike') ] add = models.ForeignKey(Add, on_delete=models.CASCADE, related_name='votes') ip_address = models.CharField(max_length=45) # 支持IPv6,最长45字符 vote_type = models.IntegerField(choices=VOTE_CHOICES) created_at = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('add', 'ip_address') # 同一IP对同一内容只能投一次票
2. 更新视图逻辑
去掉@login_required装饰器,获取用户真实IP,处理投票逻辑:
# views.py from django.shortcuts import get_object_or_404, redirect from .models import Add, Vote def get_client_ip(request): # 获取用户真实IP,兼容反向代理场景 x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[0] else: ip = request.META.get('REMOTE_ADDR') return ip def Like(request, slug): add = get_object_or_404(Add, slug=slug) user_ip = get_client_ip(request) next_url = request.POST.get("next", "/") # 先取消该IP的点踩记录(如果存在) Vote.objects.filter(add=add, ip_address=user_ip, vote_type=Vote.DISLIKE).delete() # 切换点赞状态:存在则取消,不存在则添加 existing_vote = Vote.objects.filter(add=add, ip_address=user_ip, vote_type=Vote.LIKE).first() if existing_vote: existing_vote.delete() else: Vote.objects.create(add=add, ip_address=user_ip, vote_type=Vote.LIKE) return redirect(next_url) def Dislike(request, slug): add = get_object_or_404(Add, slug=slug) user_ip = get_client_ip(request) next_url = request.POST.get("next", "/") # 先取消该IP的点赞记录(如果存在) Vote.objects.filter(add=add, ip_address=user_ip, vote_type=Vote.LIKE).delete() # 切换点踩状态:存在则取消,不存在则添加 existing_vote = Vote.objects.filter(add=add, ip_address=user_ip, vote_type=Vote.DISLIKE).first() if existing_vote: existing_vote.delete() else: Vote.objects.create(add=add, ip_address=user_ip, vote_type=Vote.DISLIKE) return redirect(next_url)
3. 调整模板显示
修改投票计数逻辑,从Vote模型中统计对应类型的票数:
<div class="rate-added-rule"> <form action="{% url 'like' added_data.slug %}" method="POST"> {% csrf_token %} <input type="hidden" name="next" value="{{ request.path }}"> <button type="submit" class="like-button"> <i class="far fa-thumbs-up">LIKE<span>VOTES: {{ added_data.votes.filter(vote_type=1).count }}</span></i> </button> </form> <form action="{% url 'dislike' added_data.slug %}" method="POST"> {% csrf_token %} <input type="hidden" name="next" value="{{ request.path }}"> <button type="submit" class="dislike-button"> <i class="far fa-thumbs-down">DISLIKE<span>VOTES: {{ added_data.votes.filter(vote_type=-1).count }}</span></i> </button> </form> </div>
4. 额外优化建议
- IP处理:如果网站部署在反向代理(如Nginx)后,要确保服务器配置中正确传递用户真实IP,否则会获取到代理服务器的IP。
- 可选Cookie辅助:如果担心同一IP下多个用户的情况,可以结合Cookie记录设备标识,进一步区分投票主体,但IP仍作为核心标识。
内容的提问来源于stack exchange,提问作者Oh Yeah
相关产品推荐
相关产品推荐

