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/
後端完成效果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章