Django前后端分离开发-新闻管理系统(四)

项目源码下载:https://github.com/Cherish-sun/NEWS/tree/master

实现新闻标签、广告的web API

一、serializers.py 添加

# 按serializers来序列化新闻标签
class TagSerializer(serializers.ModelSerializer):
    # id = serializers.Field()
    name = serializers.CharField(required=True, max_length=100)
    slug = serializers.CharField(required=True, max_length=100)

    class Meta:
        model = Tag
        fields = ('id', 'name', 'slug')


# 广告
class AdSerializer(serializers.ModelSerializer):
    class Meta:
        model = Ad
        fields = "__all__"

二、views.py中设置新闻标签、广告的Viewset

class TagViewset(viewsets.ModelViewSet):
    """
    list:
       GET url: /tag/   标签列表数据
    create:
       POST url: /tag/  创建标签详情,返回新生成的标签对像
    retrieve:
       GET url: /tag/1/  获取标签详情,返回标签对像
    update:
       PUT url: /tag/1/  修改标签详情,返回标签对像
    delete:
       DELETE url: /tag/1/  删除标签详情,返回空对像
    """
    # 用于从此视图返回对象的查询器集。
    queryset = Tag.objects.all()

    # filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
    # 查询
    # filter_class =
    # SearchFilter对应search_fields,对应模糊查询,也可用关连表的字段进行查询,但需要二个下划线连接,如categorys__title
    search_fields = ('name')
    # 用于验证和反序列化输入以及序列化输出的serializer类。通常,您必须设置此属性,或覆盖该    get_serializer_class()方法。
    serializer_class = TagSerializer
    # 应用于执行单个模型实例的对象查找的模型字段。默认为’pk’。
    lookup_field = "id"


class AdViewset(viewsets.ModelViewSet):
    """
    list:
       GET url: /ad/   广告列表数据
    create:
       POST url: /ad/  创建广告详情,返回新生成的广告对像
    retrieve:
       GET url: /ad/1/  获取广告详情,返回广告对像
    update:
       PUT url: /ad/1/  修改广告详情,返回广告对像
    delete:
       DELETE url: /ad/1/  删除广告详情,返回空对像
    """
    # 用于从此视图返回对象的查询器集。
    queryset = Ad.objects.all()

    # filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
    # 查询
    # filter_class =
    # SearchFilter对应search_fields,对应模糊查询,也可用关连表的字段进行查询,但需要二个下划线连接,如categorys__title
    search_fields = ('title')
    # 用于验证和反序列化输入以及序列化输出的serializer类。通常,您必须设置此属性,或覆盖该get_serializer_class()方法。
    serializer_class = AdSerializer
    # 应用于执行单个模型实例的对象查找的模型字段。默认为’pk’。
    lookup_field = "id"

三、将两个类注册到urls.py里

router.register(r'tag', view.TagViewset, base_name='tag')
router.register(r'ad', view.AdViewset, base_name='ad')

四、实现文章的web API

1、serializers.py 添加
# 新闻文章
class ArticleSerializer(serializers.ModelSerializer):
    # 外键相关对象
    item = ItemSerializer()
    author = UserSerializer()
    tags = TagSerializer(many=True)

    class Meta:
        model = Article
        fields = "__all__"


# 热门文章
class Hot_articleSerializer(serializers.ModelSerializer):
    item = ItemSerializer()
    author = UserSerializer()
    tags = TagSerializer(many=True)

    class Meta:
        model = Article
        fields = "__all__"
2、在article目录下新建myfilter.py
# -*- coding: utf-8 -*-

import django_filters
from django.db.models import Q
from .models import Article, Item


class ArticleFilter(django_filters.rest_framework.FilterSet):
    """
    文章的过滤类
    """
    author = django_filters.CharFilter(name='author', help_text="作者")
    status = django_filters.ChoiceFilter(name='status', help_text="状态")
    publish_date = django_filters.DateTimeFilter(name='publish_date', help_text="发布时间")
    item = django_filters.CharFilter(name='item', help_text="分类")
    tags = django_filters.CharFilter(name='tags', help_text="标签")
    # 其中method指向自己定义的过滤函数,label用于标识在测试API界面中的过滤界面字段,categorys控制查询字段
    categorys = django_filters.NumberFilter(method='item_categorys_filter', help_text="大类")

    #  top_category = django_filters.NumberFilter(method='item_categorys_filter')

    def item_categorys_filter(self, queryset, name, value):
        return queryset.filter(item__categorys=value)

    class Meta:
        model = Article
        fields = ['author', 'status', 'publish_date', 'is_active', 'item', 'categorys', 'tags']
3、views.py 添加
from rest_framework.pagination import PageNumberPagination
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters
from .myfilter import ArticleFilter
from rest_framework.response import Response


class ArticlePagination(PageNumberPagination):
    page_size = 5
    page_size_query_param = 'page_size'
    page_query_param = "page"
    max_page_size = 20


class ArticleListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
    """
    文章列表页, 分页, 搜索, 过滤, 排序
    可根据'author', 'status', 'publish_date', 'is_active', 'item', 'tags' 查询
    """
    # throttle_classes = (UserRateThrottle, )
    # 查询对象集
    queryset = Article.objects.all()
    # 序列化的类名
    serializer_class = ArticleSerializer
    # 分页,有分页列表结果时应使用的分页类。
    pagination_class = ArticlePagination
    # authentication_classes = (TokenAuthentication, )
    # 过滤、查询类
    filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
    # DjangoFilterBackend对应filter_fields属性,做相等查询
    # 过滤字段类
    filter_class = ArticleFilter
    # SearchFilter对应search_fields,对应模糊查询
    search_fields = ('title', 'item__title', 'tags__name')
    # 排序
    ordering_fields = ('id', 'publish_date')
    lookup_field = "id"

    # 重写retrieve方法,取出数据后,将浏览数加一,重新取回数据
    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        instance.read_num += 1
        instance.save()
        serializer = self.get_serializer(instance)
        return Response(serializer.data)


class Hot_articleListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    """
    热门文章

    """
    # throttle_classes = (UserRateThrottle, )
    # 查询对象集
    queryset = Article.objects.filter(is_active='True')[:10]
    # 序列化的类名
    serializer_class = ArticleSerializer
    # 排序
    ordering_fields = ('-id',)
    lookup_field = "id"

五、实现用户相关的web API(实现注册、登录、重置密码功能)

1、views.py添加
from rest_framework.authtoken.models import Token
from rest_framework.authentication import TokenAuthentication, SessionAuthentication
from rest_framework import permissions
from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST, HTTP_201_CREATED
from rest_framework.decorators import action
from rest_framework.views import APIView


 class UserViewset(viewsets.ModelViewSet):
    """
    用户查询和注册
    list:
       GET url: /user/   用户列表数据
    creat:
       POST url: /user/  创建用户详情
    retrieve:
       GET url: /user/1/  获取用户详情
    update:
       PUT url: /user/1/  修改用户详情
    delete:
       DELETE url: /user/1/  删除用户详情

    """

    # queryset = User.objects.all()
    # serializer_class = UserDetailSerializer

    def get_serializer_class(self):
        if self.action == "retrieve":
            return UserDetailSerializer
        elif self.action == "create":
            return UserRegSerializer

        return UserDetailSerializer

    # 认证策略属性
    authentication_classes = (TokenAuthentication, SessionAuthentication)

    def get_queryset(self):
        users = User.objects.filter(id=self.request.user.id)
        if users:
            for user in users:
                issuperuser = user.is_superuser
            if issuperuser:
                queryset = User.objects.all()
            else:
                queryset = users
        else:
            queryset = users
        return queryset

    permission_classes = (permissions.IsAuthenticated,)

    def get_permissions(self):
        if self.action == "retrieve":
            return [permissions.IsAuthenticated()]
        elif self.action == "create":
            return []

        return []

    # 重写create方法,给密码加密,并查询和创建token
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        passwd = request.data['password']
        user = self.perform_create(serializer)
        # 给密码加密
        user.set_password(passwd)
        user.save()
        re_dict = serializer.data
        # 查询和创建token
        token = Token.objects.get_or_create(user=user)

        serializer = UserRegSerializer({'id': user.id, 'username': user.username, 'token': token[0]})
        serializer.data["status"] = HTTP_201_CREATED
        # headers = self.get_success_headers(serializer.data)
        return Response(serializer.data)

    def perform_create(self, serializer):
        return serializer.save()


class UserLoginViewset(mixins.CreateModelMixin, viewsets.GenericViewSet):
    """
     实现用户登录
     返回用户名、ID、token
    """
    serializer_class = UserLoginSerializer

    # 因登录只需post方法,可重写create方法,取消原有保存对象逻辑,加入登录逻辑
    def create(self, request, *args, **kwargs):
        serializer = self.serializer_class(data=request.data,
                                       context={'request': request})
        if serializer.is_valid(raise_exception=True):
            user = serializer.validated_data['user']
            # 登录时,创建新的token
            tokenobj = Token.objects.update_or_create(user=user)
            token = Token.objects.get(user=user)
            # 重构返回数据
            serializer = UserLoginSerializer(
            {'username': user.username, 'id': user.id, 'password': '', 'token': token.key})
            return Response(serializer.data, status=HTTP_200_OK)
        return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)

    def get_object(self):
        return self.request.user


class UserSetPasswordViewset(mixins.CreateModelMixin, viewsets.GenericViewSet):
    """
        实现用户修改密码
        输入username、password,验证正确返回password 修改成功,否则返回HTTP_400_BAD_REQUEST
    """

    serializer_class = UserSetPasswordSerializer
    # 设置对象集
    queryset = User.objects.all()

    # 因修改密码只需post方法,可重写create方法,取消原有保存对象逻辑,加入修改密码逻辑
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            # 取出已验证的用户对象
            instance = serializer.validated_data['user']
            # 设置加密密码
            instance.set_password(request.data['newpassword'])
            # 保存
            instance.save()
            return Response({'status': 'password 修改成功'})
        else:
            return Response(serializer.errors,
                        status=HTTP_400_BAD_REQUEST)

六、实现用户收藏的web API

class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin,
                 mixins.DestroyModelMixin, viewsets.GenericViewSet):
    """
    list:
        获取用户收藏列表
    retrieve:
        判断某文章是否已经收藏
    create:
        收藏文章
    """
    # permission_classes = (permissions.IsAuthenticated, )
    # 加入认证
    authentication_classes = (TokenAuthentication, SessionAuthentication)
    lookup_field = "articles_id"
    serializer_class = UserFavSerializer

    # 重写get_queryset
    def get_queryset(self):
        if self.request.user:
            queryset = UserFav.objects.filter(user=self.request.user)
        else:
            queryset = []
        return queryset

    # 重写create
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        articleid = request.data['articles']
        userid = request.data['user']
        userfav = UserFav.objects.get_or_create(articles_id=articleid, user_id=userid)

        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=HTTP_201_CREATED, headers=headers)

到此为止,新闻管理系统后端全部代码就写完了。。。。。运行newsapi项目,打开浏览器 http://0.0.0.0:8005/


后端完成效果
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容