关于本站
1、基于Django+Bootstrap开发
2、主要发表本人的技术原创博客
3、本站于 2015-12-01 开始建站
【2018-05-23 ● 注】
这个点赞功能有点老旧,而且存在一些bug。近期我整理出了一个教程,里面重新写了点赞功能。包括ajax等等。
https://spac
参考其中的第28节和第29节。后面我更新这个应用的源码。
【以下是原文】
近期因一个项目写了一个点赞的应用,分享一下(源码地址:https://github.com/HaddyYang/django-likes)。
先思而后行,把大致的实现方法想清楚(现在是讲清楚)再开始写代码。
首先,这个点赞是可以给评论、文章等点赞。而且一般情况,需要可以点赞也可以取消点赞。
那么就需要一个主表和一个明细表。
主表是记录哪个对象被点赞的次数。明细表是记录谁什么时候点赞了或者取消点赞了。这两个表应该设计成一对多的关系,在Django中就是两个模型加一个外键即可。
大致模型在形成了,前端页面可以通过该模型获取对应的点赞数量。可以通过ajax提交点赞请求或者取消点赞请求。获取点赞的数量可以不用写处理方法,直接使用即可。而处理点赞和取消点赞的请求就需要写相关的处理方法。考虑到是ajax的方法提交请求的,那么后台处理数据需要用json的数据结构返回结果比较适合。
这里点赞可以给其他任意对象实现点赞功能,那么需要引入ContentType这个东西。
如果对数据库开发比较好的人员就很容易明白这个是什么作用。简单来说,就是给主表加两个字段,一个是对象类型,一个是对象的ID。这样就可以以不变应万变。不管你对象是什么,只要填这两个字段就可以区分清楚。
大致模型(models.py文件)如下:
#coding:utf-8 __author__ = 'Haddy Yang(Ysh)' __start_date__ = '2016-06-12' """ likes app """ from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.auth.models import User #likes number model class Likes(models.Model): #content type content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = GenericForeignKey( ct_field="content_type", fk_field="object_id" ) #likes number likes_num = models.IntegerField(default = 0) def __unicode__(self): return u'%s:%s(%s)' % (self.content_type, self.object_id, self.likes_num) #likes detail recode class LikesDetail(models.Model): likes = models.ForeignKey(Likes) user = models.ForeignKey(User) is_like = models.BooleanField(default = False) pub_date = models.DateTimeField(auto_now=True) class Meta: ordering=['-pub_date']
Likes就是对应主表,里面有ContentType两个字段和记录点赞数量一个字段。
LikesDetail是对应明细表,记录哪个用户对哪个对象点赞或者取消点赞。这里的用户我使用Django自带的用户系统。你可以对应修改一下,也可以修改成不用登录用户就可以点赞。
处理方法这里一开始写了两个。其中一个是获取点赞的数量,这个用处不大,可以直接通过模型获取到数量。这个可以忽略(有兴趣可以看源码)。主要的处理方法就是处理点赞和取消点赞。具体代码(views.py文件)如下:
#coding:utf-8 __author__ = 'Haddy Yang(Ysh)' __start_date__ = '2016-06-12' """ likes views """ from django.shortcuts import render from django.http import HttpResponse import json from likes.models import Likes, LikesDetail from django.contrib.contenttypes.models import ContentType #导入likes下自定义的装饰器(decorator.py文件) from likes.decorator import check_login, check_request @check_login @check_request('type', 'id', 'direct') def likes_change(request): u"""处理改变点赞状态 Method: GET params: type : object type id : object id direct: -1 or 1 (add like or remove like) return: json """ #创建json对象需要的数据 data = {} data['status'] = 200 data['message'] = u'ok' data['nums'] = 0 #获取数据和对应的对象 obj_type = request.GET.get('type') obj_id = request.GET.get('id') user = request.user direct = 1 if request.GET.get('direct') == '1' else -1 c = ContentType.objects.get(model = obj_type) #获取Likes对象 try: l = Likes.objects.get(content_type = c, object_id = obj_id) except Exception, e: #没有获取到对象,则新增一个Likes对象 l = Likes(content_type = c, object_id = obj_id) data['nums'] = l.likes_num #获取Likes明细对象 try: detail = LikesDetail.objects.get(likes = l, user = user) except Exception, e: detail = LikesDetail(likes = l, user = user, is_like = False) liked = 1 if detail.is_like else -1 #判断是否赞过,或者取消赞 if liked == direct: data['status'] = 403 data['message'] = u'Invalid operation' else: #更新记录 l.likes_num += direct if l.likes_num < 0: l.likes_num = 0 l.save() data['nums'] = l.likes_num #修改明细 detail.is_like = direct == 1 detail.save() #返回结果 return HttpResponse(json.dumps(data), content_type="application/json")
大致实现方法是:通过GET请求提交三个参数(type, id, direct)。
type是对应要给某个对象点赞的模型名称;
id就是这个对象的id值;
direct有两个值:-1和1,1代表点赞,-1代表取消点赞。
然后根据这3个参数获取Likes模型对象,判断是否有对应的记录,若没有则创建对象。
获取到Likes对象之后,再根据其id获取对应用户的明细记录。
这里的明细只控制一条明细。因为这个明细信息全部记录没什么作用。而且比较容易产生点赞行为,导致数据库数据增长快。所以这里处理成只对一条明细读写。
另外,眼睛尖的人可能发现我在这个方法上面加了两个装饰器。一个是检查是否有登录用户的;一个是检查GET请求提供的参数是否齐全。这两个装饰器的代码写在这个应用目录下的decorator.py文件。代码如下:
#coding:utf-8 __author__ = 'Haddy Yang(Ysh)' __start_date__ = '2016-06-12' """ likes decorators """ from django.http import HttpResponse import json #装饰器,检测是否有登录用户 def check_login(func): u"""检查是否登录用户""" def warpper(request): if request.user.is_authenticated(): #若有登录,则继续执行方法 return func(request) else: #若未登录,不处理 data = {} data['status'] = 401 data['message'] = u'no login' return HttpResponse(json.dumps(data), content_type="application/json") return warpper #装饰器,检查request参数是否齐全 def check_request(*params): def __check_request(func): def warpper(request): #print params #遍历参数 for param in params: #print param #判断参数是否存在 if not request.GET.has_key(param): data = {} data['status'] = 402 data['message'] = u'no params:%s' % param return HttpResponse(json.dumps(data), content_type="application/json") #参数都存在,则继续执行 return func(request) return warpper return __check_request
这两个装饰器也是比较典型,一个是普通的装饰器;一个是装饰器可以带参数(就像函数带参数一样的使用)。同样,这两个装饰器如果不符合条件的话,就返回json数据。若符合条件,就继续执行。
其他设置可以看看源码,例如urls。而且这个主要使用ajax获取数据,所以不需要创建html页面模版。
可以在我的github上下载源码:https://github.com/HaddyYang/django-likes
1、把应用复制到你的Django项目中。
2、设置settings.py文件,引入该应用。
INSTALLED_APPS = [ 'likes', #加入这个 #others... ]
3、添加链接路由到项目的路由中,打开项目的urls.py文件。
urlpatterns = [ url(r'^admin/', admin.site.urls), #打开Django项目的urls.py文件,加入这个 url(r'^likes/', include('likes.urls')), ]
4、同步更新一下数据库。
python manager.py makemigrations python manager.py migrate
5、然后你对应修改前端页面。例如通过likes的对象模型获取点赞数量、用ajax方法提交点赞请求或者取消点赞。
/likes/likes_change?type=blog&id=1&direct=1
这个是给对象为blog,id为1的对象点赞+1。
/likes/likes_change?type=blog&id=1&direct=-1
这个是给对象为blog,id为1的对象取消点赞。
github源码地址:https://github.com/HaddyYang/django-likes
igoab1990@163.com
谢谢分享
2018-05-24 19:23 回复