DRF实操学习——文章和评论的设计

ops/2024/10/20 11:01:29/

DRF实操学习——文章和评论的设计

  • 1.文章表的设计
  • 2.文章表接口演示
    • 基础权限
    • 创建文章
    • 修改文章
    • 删除文章
    • 浏览所有文章
  • 3.评论表的设计
  • 4.评论表接口演示
    • 1. 查询指定文章下的所有评论

1.文章表的设计

  1. 创建一个community的app
    在这里插入图片描述
  2. 在settings中 完成注册
    在这里插入图片描述
  3. 定义模型
    创建文章表
python">from django.db import models
from work.models import Label
from django.contrib.auth.models import User
# Create your models here.
from utils.modelsMixin import ModelSetMixinclass Article(ModelSetMixin):STATUS_CHOICES = ((0,'未发布'),(1,'发布'),)title = models.CharField(max_length=100,verbose_name='标题')digest = models.CharField(max_length=300,verbose_name='摘要')content = models.TextField(verbose_name='文章内容')page_view = models.IntegerField(verbose_name='浏览量',default=0)priority = models.IntegerField(verbose_name='优先级',default=0)status = models.IntegerField(verbose_name='状态',default=0,choices=STATUS_CHOICES)label = models.ForeignKey(Label,on_delete=models.CASCADE)user = models.ForeignKey(User,on_delete=models.CASCADE)class Meta:# 按照priority、page_view、create_time进行倒叙排序ordering = ["-priority","-page_view","-create_time"]db_table = 'article' #定义生成的mysql表名verbose_name = '文章'verbose_name_plural = verbose_name
  1. 创建序列化器
python">from rest_framework.serializers import ModelSerializer#有对应的模型,可以继承ModelSerializer
class ArticleSerializer(ModelSerializer): class Meta:model = Articleexclude = ['is_delete']
  1. 创建视图
python">from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet
from .serializers import *
# Create your views here.
class ArticleViewSet(ModelViewSet):queryset = Article.objects.filter(is_delete=False)serializer_class = ArticleSerializer
  1. 创建路由
python">from rest_framework.routers import DefaultRouterfrom .views import *urlpatterns = []
router = DefaultRouter()
router.register('article', ArticleViewSet)
urlpatterns += router.urls
  1. 创建主路由
    在这里插入图片描述

2.文章表接口演示

基础操作分析:
创建文章:登录。自动获取当前登录的用户,作为文章的作者
修改文章:创建者
删除文章:创建者
浏览所有文章:登录
查看指定文章:登录

基础权限

由上面分析得知,最基础的权限是登录,所以我们在视图中增加基础权限的配置
在这里插入图片描述

创建文章

分析:获取当前登录用户为文章的创建者

  1. 重写create方法
python">    #@auto_user自定义装饰器将当前登录的用户作为创建者,在前端就不需要传入user,后端会自动拿到当前登录的user作为文章的创建者@auto_user def create(self,request,*args,**kwargs):return ModelViewSet.create(self,request,*args,**kwargs)
  1. 序列化器的优化,对返回的数据进行优化
python">from rest_framework.serializers import ModelSerializer
from rest_framework import serializers
from .models import *#有对应的模型,可以继承ModelSerializer
class ArticleSerializer(ModelSerializer): user_name = serializer.CharField(source='user.username',read_only=True)user_avatar = serializer.CharField(source='user.userdetail.avatar',read_only=True)label_name = serializer.CharField(source='label.name',read_only=True)class Meta:model = Articleexclude = ['is_delete']
  1. 补充:permission.py中的权限代码如下,后续修改文章、查询文章等涉及到权限的操作都会使用到本文件
python">
from functools import update_wrapperfrom django.contrib.auth.models import Group
from rest_framework.permissions import BasePermissionclass TeacherPermission(BasePermission):def has_permission(self, request, view):user = request.user  # 当前请求的用户信息# 判断身份,查询用户在不在老师这个分组里面group = Group.objects.filter(name='老师').first()user_groups = user.groups.all()return user.is_superuser or group in user_groupsclass ActiveUserPermission(BasePermission):def has_permission(self, request, view):# 操作的用户必须是当前登陆的用户user = request.userreturn user.id == int(view.kwargs['pk'])class ActiveUserPPermission(BasePermission):def has_permission(self, request, view):# 操作的用户必须是当前登陆的用户user = request.userreturn user.id == int(request.data.get('user'))class RootPermission(BasePermission):def has_permission(self, request, view):user = request.userreturn user.is_superuser# 更改权限装饰器
def wrap_permisssion(*permissions, validate_permisssion=True):def decorator(func):def wrapper(self, request, *args, **kwargs):self.permission_classes = permissionsif validate_permisssion:self.check_permissions(request)return func(self, request, *args, **kwargs)return update_wrapper(wrapper, func)return decoratordef auto_user(func):def wrapper(self, request, *args, **kwargs):request.POST._mutable = True  # 让请求参数可以被修改request.data['user'] = request.user.idreturn func(self, request, *args, **kwargs)return wrapper

修改文章

分析:文章的发布者才能修改文章。这里需要在定义一个装饰器判断该用户是否是该文章的发布者。
使用装饰器的场景:在原有功能的基础上,再增加额外的功能。

  1. 在permission.py中增加装饰器update_auto_user
python">def update_auto_user(func):def wrapper(self, request, *args, **kwargs):# 判断当前操作的用户是不是这个数据的创建者# 设:文章的id为1,作者的id为3,当前登录的用户id为5# 所有的没有被逻辑删除的文章数据集里面的id等于1,并且user用户为5,查不到作者id为3的数据# self.get_queryset()可以应用于所有的视图集res = self.get_queryset().filter(id=kwargs['pk'],user=request.user)if not res:return Response({'detail':'您没有修改的权限'})# 修改不可以更改作者,只能是当前的登录用户request.POST._mutable = True  # 让请求参数可以被修改request.data['user'] = request.user.idreturn func(self, request, *args, **kwargs)return wrapper
  1. 重写update方法
python">    @update_auto_userdef update(self, request, *args, **kwargs):return ModelViewSet.update(self, request, *args, **kwargs)

删除文章

分析:只有作者才能删除文章

  1. 在permission.py中增加装饰器destory_auto_user
python">def destory_auto_user(func):def wrapper(self, request, *args, **kwargs):res = self.get_queryset().filter(id=kwargs['pk'],user=request.user)if not res:return Response({'detail':'您没有删除的权限'})return func(self, request, *args, **kwargs)return wrapper
  1. 重写destory方法
python">    @destory_auto_userdef destory(self, request, *args, **kwargs):return ModelViewSet.update(self, request, *args, **kwargs)

浏览所有文章

分析:针对不同的操作,查询集不同,比如,用户查看文章不能查看到草稿的数据,作者查看文章可以查看到自己的已发布的和未发布的数据

  1. 配置分页器
python">from rest_framework.pagination import PageNumberPagination
class ArticlePaginationPageNumber(PageNumberPagination):page_size = 10  # 默认每页多少条,如果不传size,默认3条#page_size_param  = 'page' #定义传入页数的参数,默认为pagepage_size_query_param = 'size'  # 规定哪个参数为分页大小参数,参数可以自己定义,这里定义为size,则前端传入参数size = 10,每页展示10条,但是不会超过设置的最大每页条数100max_page_size = 100  # 最大每页多少条class ArticleViewSet(ModelViewSet):queryset = Article.objects.filter(is_delete=False)serializer_class = ArticleSerializerpermission_classes = [IsAuthenticated]#在视图中增加分页器类pagination_class = ArticlePaginationPageNumber
  1. 根据不同的操作设置不同的查询集。重写get_queryset方法
python">class ArticleViewSet(ModelViewSet):queryset = Article.objects.filter(is_delete=False)serializer_class = ArticleSerializerpermission_classes = [IsAuthenticated]pagination_class = ArticlePaginationPageNumber# 重写get_queryset方法的场景:根据不同的操作场景设置不同的查询集def get_queryset(self):if self.action in ['list','retrieve']: #如果是查询,则只能返回已发布的文章数据return Article.objects.filter(is_delete=False,status=1)return self.queryset#@auto_user自定义装饰器将当前登录的用户作为创建者,在前端就不需要传入user,后端会自动拿到当前登录的user作为文章的创建者@auto_user def create(self,request,*args,**kwargs):return ModelViewSet.create(self,request,*args,**kwargs)@update_auto_userdef update(self, request, *args, **kwargs):return ModelViewSet.update(self, request, *args, **kwargs)@destory_auto_userdef destory(self, request, *args, **kwargs):return ModelViewSet.update(self, request, *args, **kwargs)
  1. 查看作者自己的所有文章数据:包括已发布的和未发布的
python">    @action(methods=['get'],detail=False)def my(self,request):"""得到用户自己的数据,包括未发布数据"""# 用户为当前登录的用户data = self.get_queryset().filter(user=request.user) serializer = self.get_serializer(data,many=True)return Response(serializer.data)
  1. 浏览量增加接口
    分析:点击进入文章,浏览量+1。
    重写retrieve方法
python">    def retrieve(self, request, *args, **kwargs):"""重写retrieve方法,点击文章,增加浏览量"""# F查询可以拿到这个字段的值self.get_queryset().filter(id=kwargs['pk']).update(page_view=F('page_view')+1)return ModelViewSet.update(self, request, *args, **kwargs)

补充:如果不想被刷浏览量,前端写延时器,10s之后调用接口。增加额外的增加浏览量的接口,retrieve可以记录客户端传入的id,然后判断时间。

3.评论表的设计

  1. 在community的models文件下创建评论模型
python"># 评论表
class Comment(ModelSetMixin):content = models.TextField(verbose_name='评论的内容')level = models.IntegerField(verbose_name='评论等级',default=1)# 因为在文章下的评论没有父级评论,所以null=True允许为空# 父级评论的idparent_comment = models.IntegerField(verbose_name='父级评论',null=True)# 回复评论的id,因为有可能是回复父级评论下面的子评论,所以要增加这个字段reply_comment = models.IntegerField(verbose_name='回复评论',null=True)# 一篇文章可以有多条评论article = models.ForeignKey(Article,on_delete=models.CASCADE)# 一个用户可以评论多条评论user = models.ForeignKey(User,on_delete=models.CASCADE)class Meta:# 按照create_time进行倒叙排序ordering = ["-create_time"]db_table = 'comment' #定义生成的mysql表名verbose_name = '评论'verbose_name_plural = verbose_name
  1. 定义序列化器
python">class CommentSerializer(ModelSerializer): class Meta:model = Commentexclude = ['is_delete']
  1. 编写视图
    分析:评论不需要更新和查询所有,所以继承GenericViewSet
python">class CommentViewSet(GenericViewSet,CreateModelMixin,DestroyModelMixin):queryset = Comment.objects.filter(is_delete=False,article__status=1)serializer_class = CommentSerializerpermission_classes = [IsAuthenticated]@auto_user def create(self,request,*args,**kwargs):return ModelViewSet.create(self,request,*args,**kwargs)@destory_auto_userdef destory(self, request, *args, **kwargs):return ModelViewSet.update(self, request, *args, **kwargs)
  1. 增加路由
python">from rest_framework.routers import DefaultRouterfrom .views import *urlpatterns = []
router = DefaultRouter()
router.register('article', ArticleViewSet)
router.register('comment', CommentViewSet)
urlpatterns += router.urls
  1. 在文章表中增加__str__方法
    在这里插入图片描述
    这样在评论表中的article外键就会展示出对应的内容
    在这里插入图片描述

4.评论表接口演示

1. 查询指定文章下的所有评论

分析:
/article/1/comment
给文章视图集编写一个额外的功能,返回该文章的所有评论
在ArticleViewSet中增加接口如下:

python">    @action(methods=['get'],detail=True)def comment(self,request,pk):# article_id=pk联表查询# 查看所有的评论中文章id为传入的pk,等级为1的评论comments = Comment.objects.filter(article_id=pk,level=1)serializer = CommentSerializer(comments,many=True)return Response(serializer.data)

优化返回结果,修改序列化器:

python"># 定义子评论的序列化器
class SonCommentSerializer(ModelSerializer):user_name = serializer.CharField(source='user.username',read_only=True)user_avatar = serializer.CharField(source='user.userdetail.avatar',read_only=True)reply_username = SerializerMethodField()model = Commentexclude = ['is_delete']def get_reply_username(self,comment):# 查询出被回复评论的用户的用户名return Comment.objects.get(id=comment.reply_comment).user.usernameclass CommentSerializer(ModelSerializer): user_name = serializer.CharField(source='user.username',read_only=True)user_avatar = serializer.CharField(source='user.userdetail.avatar',read_only=True)# 返回当前评论的子评论sonComment = SerializerMethodField()class Meta:model = Commentexclude = ['is_delete']# get_+自定义的roleDetail名字  comment保存当前要操作的模型对象def get_sonComment(self, comment):serializer = SonCommentSerializer(Comment.objects.filter(parent_comment=comment.id),many=True)data = serializer.data# 将获取的子评论进行反转,第一个评论在第一位,而不是时间最新的在最前面# reverse对列表做反转data.reverse()return data

返回结果如下:
在这里插入图片描述
前端效果:
在这里插入图片描述


http://www.ppmy.cn/ops/119787.html

相关文章

【Unity服务】如何使用Unity Version Control

Unity上的线上服务有很多,我们接触到的第一个一般就是Version Control,用于对项目资源的版本管理。 本文介绍如何为项目添加Version Control,并如何使用,以及如何将项目与Version Control断开链接。 其实如果仅仅是对项目资源进…

Clickhouse分布式表初体验

ClickHouse的分布式表是一种特殊类型的表,它允许你跨多个节点进行数据的查询和写入操作。以下是创建分布式表的步骤和案例: 1. 创建本地表: 在集群的每个节点上创建一个本地表,可以使用ReplicatedMergeTree系列引擎来实现数据…

电脑录屏怎么录视频和声音?苹果macOS、windows10都可以用的原神录屏工具来啦

在当今数字化时代,电脑录屏已经成为一项非常实用的技能,无论是制作教学视频、记录游戏精彩瞬间,还是进行线上会议演示,都离不开高质量的录屏。那么,电脑录屏怎么录视频和声音呢?今天就为大家详细介绍一下&a…

【数据库】 MongoDB 查看当前用户的角色和权限

在 MongoDB 中,可以通过一些简单的命令查看当前用户的角色和权限。这对于理解用户的访问能力和管理用户权限至关重要。 1. 使用 MongoDB Shell 查看角色和权限 1.1 查看当前数据库用户 要查看当前数据库中的所有用户及其角色,可以使用以下命令&#x…

带你0到1之QT编程:二十二、QChart类图表及折线图、直方图、饼图的三大可视化图表实战!

此为QT编程的第二十二谈!关注我,带你快速学习QT编程的学习路线! 每一篇的技术点都是很很重要!很重要!很重要!但不冗余! 我们通常采取总-分-总和生活化的讲解方式来阐述一个知识点!…

达梦8-DTS迁移测试-从Oracle迁移到达梦

1、目的 将Oracle数据库的SCOTT用户下的表迁移到达梦8。 2、数据库信息 2.1 Oracle端 操作系统 Redhat 7.5 数据库架构 单机 数据库版本 Oracle 19c 待迁移数据库名 prodpdb 待迁移的对象 SCOTT IP/端口 192.168.6.121:1521 用户名/密码 scott/tiger 字符集编…

VIIRS 版本1(5000)数据于2024年6月17日停更,请转向VIIRS版本2(5200)

根据官网发布的消息,VIIRS版本1(5000)的多数数据产品于今日停止更新。需要VIIRS数据的朋友需要转向版本2数据了。 可见红外成像辐射计套件 (VIIRS) 第 1 版 (集合 1) 陆地数据产品于 2024 年 6 月 17 日终止生产。唯一的例外是双向反射分布函…

在Ubuntu 14.04上安装带SSL的Webmin的方法

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。 简介 Webmin 是一个基于 Web 的类 Unix 系统管理工具。它提供了一个简单的替代方案来进行命令行系统管理,并可以通过提供的…