Django点赞功能实现

  • 发布时间:2016年6月15日 15:55
  • 作者:杨仕航
  • 分类标签: Django
  • 阅读(16214)
  • 评论(1)

【2018-05-23 ● 注】

这个点赞功能有点老旧,而且存在一些bug。近期我整理出了一个教程,里面重新写了点赞功能。包括ajax等等。

https://space.bilibili.com/252028233/#/channel/detail?cid=28138

参考其中的第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页面模版。


   如何加入到你的Django项目:

可以在我的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

上一篇:我对Python装饰器的理解

下一篇:我的网站搭建(第20天) 修改昵称和密码

评论列表

igoab1990@163.com

igoab1990@163.com

谢谢分享

2018-05-24 19:23 回复

新的评论

清空