如何在无需用户认证的情况下为Django语录应用添加点赞功能?
无需登录实现Django语录点赞功能的方案
核心思路
通过客户端唯一标识(Cookie 或简易设备指纹)记录用户的点赞行为,结合后端校验逻辑,避免同一用户重复点赞。
具体实现步骤
1. 扩展语录模型,添加点赞相关字段
在你的Quote模型中新增两个字段:一个存储点赞总数,一个存储已点赞用户的唯一标识列表(用JSON格式存储多个标识)。
# models.py from django.db import models from django.contrib.postgres.fields import JSONField # 使用PostgreSQL时用这个,普通数据库可替换为TextField并手动序列化JSON class Quote(models.Model): content = models.TextField(verbose_name="语录内容") like_count = models.IntegerField(default=0, verbose_name="点赞数") liked_user_ids = JSONField(default=list, verbose_name="已点赞用户标识列表") def __str__(self): return self.content[:50]
2. 生成并维护客户端唯一标识
用户访问页面时,检查是否存在自定义Cookie(比如user_identifier),无则生成随机字符串作为标识,返回给客户端并长期保存。
# views.py import uuid from django.shortcuts import render def quote_list(request): # 获取或生成用户唯一标识 user_id = request.COOKIES.get('user_identifier') if not user_id: user_id = str(uuid.uuid4()) quotes = Quote.objects.all() # 给每条语录标记当前用户是否已点赞 for quote in quotes: quote.is_liked = user_id in quote.liked_user_ids response = render(request, 'quotes/list.html', {'quotes': quotes}) # 首次访问时设置Cookie,有效期设为30天 if not request.COOKIES.get('user_identifier'): response.set_cookie('user_identifier', user_id, max_age=30*24*60*60) return response
3. 实现点赞接口逻辑
编写POST视图处理点赞请求,校验用户标识是否已存在于该语录的点赞列表中,未存在则更新点赞数和标识列表。
# views.py from django.http import JsonResponse from django.views.decorators.http import require_POST from .models import Quote @require_POST def like_quote(request, quote_id): try: quote = Quote.objects.get(id=quote_id) user_id = request.COOKIES.get('user_identifier') if not user_id: return JsonResponse({'status': 'error', 'message': '用户标识无效'}, status=400) if user_id not in quote.liked_user_ids: quote.like_count += 1 quote.liked_user_ids.append(user_id) quote.save() return JsonResponse({'status': 'success', 'like_count': quote.like_count}) else: return JsonResponse({'status': 'info', 'message': '你已经点过赞了'}) except Quote.DoesNotExist: return JsonResponse({'status': 'error', 'message': '语录不存在'}, status=404)
4. 前端页面添加点赞交互
在模板中渲染点赞按钮,通过AJAX发送请求并实时更新页面状态。
<!-- templates/quotes/list.html --> {% for quote in quotes %} <div class="quote-card"> <p>{{ quote.content }}</p> <button class="like-btn" data-quote-id="{{ quote.id }}" {% if quote.is_liked %}disabled{% endif %}> 点赞({{ quote.like_count }}) </button> </div> {% endfor %} <script> document.querySelectorAll('.like-btn').forEach(btn => { btn.addEventListener('click', function() { const quoteId = this.dataset.quoteId; fetch(`/like/${quoteId}/`, { method: 'POST', headers: { 'X-CSRFToken': '{{ csrf_token }}', 'Content-Type': 'application/json' } }) .then(res => res.json()) .then(data => { if (data.status === 'success') { this.textContent = `点赞(${data.like_count})`; this.disabled = true; } else { alert(data.message); } }); }); }); </script>
5. 方案优缺点说明
- 优点:实现简单,对用户无感知,兼容性强,满足简易应用的需求。
- 缺点:用户清除Cookie、更换浏览器/设备后可重复点赞;若需更严格的防刷赞,可结合IP+浏览器User-Agent生成标识,但仍无法完全杜绝刷赞(如同一局域网多用户共享IP)。如果是高并发或对数据准确性要求高的场景,建议引导用户注册登录。
内容的提问来源于stack exchange,提问作者E4crypt3d
相关产品推荐
相关产品推荐

