Django入门:实现收藏操作

     阅读:63

一、系统概述:

做毕设前先练练手,使用django搭建一个简单的小说系统;(项目打包在结尾)

用户可以登录:

登录后可以浏览系统界面:

点击详情进入详情界面:点击收藏按钮,即可收藏小说。再次点击取消收藏。

用户主页展示已经收藏的小说条目:


二、详细设计

1.model设计

model里有三个模型:用户模型,小说模型,收藏模型

其实就像课程关系、学生关系、选课关系一样。选课关系引入学生id、课程id作为外键,记录哪个学生选了哪些课。(为什么不直接用models.ManyToManyField,而要添加一个‘选课模型’呢?因为有数据库方面的好处,详见《数据库系统教程·第3版》)

# 用户模型
class User(models.Model):
    username = models.CharField(max_length=50)  # 用户账号
    password = models.CharField(max_length=50)  # 用户密码

    def toDict(self):
        return {'id': self.id, 'username': self.username, 'password': self.password}

    class Meta:
        db_table = "user"  # 更改表名


# 小说模型
class Novel(models.Model):
    title = models.CharField(max_length=60)  # 小说标题
    author = models.CharField(max_length=40)  # 小说作者

    def toDict(self):
        return {'id': self.id, 'title': self.title, 'author': self.author}

    class Meta:
        db_table = "novel"  # 更改表名


# 收藏模型,记录谁收藏,收藏了什么,收藏时间。
class CltNovel(models.Model):
    who_clt = models.ForeignKey(to=User, on_delete=models.CASCADE)  # 谁收藏
    clt_relation_novel = models.ForeignKey(to=Novel, on_delete=models.CASCADE)  # 收藏了哪篇小说
    clt_time = models.DateTimeField(default=datetime.now)  # 收藏时间

    class Meta:
        db_table = "cltnovel"  # 更改表名

2.views设计

2.1 登录views

from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.urls import reverse
from user.models import User, CltNovel


# 用户主页
def index(request):
    """用户主页"""
    # 用户空间展示收藏夹
    fmod = CltNovel.objects
    uid = request.session['user']['id']  # 获取当前哪个用户登录
    fav_list = fmod.filter(who_clt_id=uid)  # 获取用户的所有收藏
    context = {'favourite_list': fav_list}

    return render(request, 'user/index.html', context)


# 用户登录表单
def login(request):
    return render(request, 'user/login.html')


# 处理用户登录
def dologin(request):
    try:
        # 执行账号校验
        user = User.objects.get(username=request.POST['usern'])
        s = request.POST['passw']

        # 检验成功
        if s == user.password:
            # 将当前登录成功的用户信息以user为key写入session中
            request.session['user'] = user.toDict()
            # 重定向到后台管理首页
            return redirect(reverse('user_index'))
        else:
            # 登录失败
            context = {'info': '密码错误!'}

    except Exception as err:
        print(err)
        context = {'info': '账号不存在!'}
    return render(request, 'user/login.html', context)


# 用户退出
def logout(request):
    del request.session['user']
    return redirect(reverse('user_login'))


# 删除收藏
def delete_fav(request):
    fav_id = request.GET.get('id')
    print(fav_id)
    return HttpResponse(fav_id)

2.2 前端views

from django.shortcuts import render
from user.models import Novel, CltNovel


def index(request):
    """前台主页,展示所有的小说条目"""
    nmod = Novel.objects  # 实例化对象
    list1 = nmod.all()  # 展示所有小说条目
    context = {'novellist': list1}
    return render(request, 'web/index.html', context)


def detail(request):
    """跳转到详情界面"""
    nid = request.GET.get('nid')  # 接受到主页面要跳转到哪个小说的id
    nmod = Novel.objects  # 实例化对象

    # 如果收藏夹里尚未有这个收藏:那个按钮应该是空心的。传送fav_status来表示收藏状态
    uid = request.session['user']['id']  # session中提取当前登录的用户
    fav_list = CltNovel.objects.filter(who_clt_id=uid)  # 找出所有该用户的收藏
    if fav_list.filter(clt_relation_novel_id=nid):  # 检查有没有该小说id
        fs = 1  # 已收藏
    else:
        fs = 0  # 未收藏

    # todo filter和get的区别:filter筛选所有条件,queryset返回列表;get返回一个,有多个或没有找到会报错
    n = nmod.get(id=nid)
    context = {'novel_detail': n, 'fav_status': fs}
    return render(request, 'web/detail.html', context)

2.3 收藏夹操作views

from datetime import datetime
from django.http import HttpResponse
from user.models import CltNovel


# 收藏夹操作
def handle(request):
    try:
        sid = request.GET.get('id')  # 前端获取被点击的小说id
        uid = request.session['user']['id']  # session中提取是哪个用户要保存,即当前登录的用户
        cltn = CltNovel()

        # 如果收藏夹里尚未有这个收藏:那就收藏这个条目
        # 如果收藏夹里已经有了,那就取消收藏
        fav_list = CltNovel.objects.filter(who_clt_id=uid)  # 找出所有该用户的收藏
        if fav_list.filter(clt_relation_novel_id=sid):  # 检查有没有该小说id
            fav_list.filter(clt_relation_novel_id=sid).delete()  # 收藏夹里已经有了,取消收藏
            return HttpResponse('♡')
        else:
            cltn.who_clt_id = uid
            cltn.clt_relation_novel_id = sid
            cltn.clt_time = datetime.now()
            cltn.save()  # 收藏夹里尚未有这个收藏:收藏这个条目
            return HttpResponse('♥')
    except Exception as err:
        print('失败,', err)

3.templates设计

3.1 user index 用户主页

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户主页</title>
    <script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
</head>
<body>
    <h1>这是用户主页!</h1>
    <div class="pull-right">
        <a href="{% url 'user_logout' %}" class="btn btn-default btn-flat">退 出</a>
        <p>我是:{{ request.session.user.username }}</p>
    </div>
    <div class="box-body table-responsive no-padding">
        <table class="table table-hover">
            <tr>
                <th>收藏编号</th>
                <th>小说编号</th>
                <th>小说标题</th>
                <th>小说作者</th>
            </tr>
            {% for vo in favourite_list %}
            <tr>
                <td>{{ vo.id }}</td>
                <td>{{ vo.clt_relation_novel.id }}</td>
                <td>{{ vo.clt_relation_novel.title }}</td>
                <td>{{ vo.clt_relation_novel.author }}</td>
            </tr>
        {% endfor %}
        </table>
    </div>
</body>
</html>

3.2 user login 用户注册表格

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户登录表单</title>
</head>
<body>
    <h1>这是用户登录表单!</h1>
    <p class="login-box-msg" style="color:red">{{ info }}</p>
    <form action="{% url 'user_dologin' %}" method="post">
        {% csrf_token %}
            <input type="text" name="usern" class="form-control" placeholder="账号">
            <input type="password" name="passw" class="form-control" placeholder="密码">
            <button type="submit" class="btn btn-primary btn-block btn-flat">登录</button>
    </form>
</body>
</html>

3.3 web index 前端系统主页面

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>小说系统首页</title>
    <script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>

    <script>
        function clickMe() {

        }
    </script>
</head>
<body>
    <h1>这是小说系统的首页!</h1>
    <div class="box-body table-responsive no-padding">
        <table class="table table-hover">
            <tr>
                <th>ID</th>
                <th>小说名称</th>
                <th>小说作者</th>
                <th>操作</th>
            </tr>
            {% for vo in novellist %}
            <tr>
                <td>{{ vo.id }}</td>
                <td>{{ vo.title }}</td>
                <td>{{ vo.author }}</td>
                <td>
                    <a href="{% url 'web_detail' %}?nid={{ vo.id }}">详情</a>
                </td>
            </tr>
            {% endfor %}
            </table>
    </div>
</body>
</html>

3.4 web detail 小说详情页面

使用ajax,点击一下就发送该小说id给views,表示要对这个小说收藏或取消收藏;

经过后端处理后,给收藏按变色。♥代表已收藏,♡代表未收藏。

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>小说详情</title>
    <script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
    <script>
        function clickSaveFav(){
            // 发送异步ajax请求,发送get
            $.ajax({
                type: "get",
                url: "{% url 'web_favourite_handle' %}",
                data: "id={{ novel_detail.id }}",
                success: function (response) {
                    let bt = document.getElementById("save_favourite")
                    bt.innerHTML = response
                }
            })
        }
    </script>
</head>
<body>
    <h1>这是小说详情界面</h1>
    <p>编号: {{ novel_detail.id }}</p>
    <p>标题: {{ novel_detail.title }}</p>
    <p>作者: {{ novel_detail.author }}</p>
    <p>操作: <button id="save_favourite" onclick="clickSaveFav()">
        {% if fav_status %}
            ♥
        {% else %}
            ♡
        {% endif %}
    </button></p>
</body>
</html>

三、源码

源码在这里:

链接:https://pan.baidu.com/s/1-25gju_JpDwJaF0ql_By1A?pwd=augj 
提取码:augj

有用请赞