用Django REST framework 編寫RESTful API(1.構(gòu)建基礎(chǔ)API)

  • 這篇文章會(huì)從由 rest framework 的 viewsets, router, ModelSerializer 構(gòu)建的一個(gè)基礎(chǔ)的 API 開始, 然后對(duì)其進(jìn)行自定義.
  • 建議閱讀部分 rest framework 的教程
  • 版本 :
  • Django==2.0.1
  • djangorestframework==3.7.7
  • Github地址

其它:

通過 viewsets, router, ModelSerializer 構(gòu)建一個(gè)關(guān)于博客的 API

構(gòu)建博客的 model

一篇文章需要有:

  • 標(biāo)題
  • 文章主體
  • 發(fā)布時(shí)間
  • 標(biāo)簽
  • 作者

標(biāo)簽和文章的關(guān)系應(yīng)該是多對(duì)多(一篇文章可以有多個(gè)標(biāo)簽,一個(gè)標(biāo)簽可以關(guān)聯(lián)多篇文章)
作者和文章的關(guān)系應(yīng)該是一對(duì)多(一個(gè)作者可以有多篇文章,一篇文章只有一個(gè)作者)
需要的model有三個(gè): 文章(Post), 標(biāo)簽(Tag), 作者(User)

class Post(models.Model):
    """
    title:標(biāo)題
    body:主體
    pub_time:發(fā)布時(shí)間
    tag:標(biāo)簽,多對(duì)多
    author:作者,一對(duì)多
    """
    title = models.CharField(max_length=100, blank=True, default='')
    body = models.TextField()
    pub_time = models.DateTimeField(auto_now_add=True)
    tags = models.ManyToManyField('Tag', related_name='posts', blank=True)
    author = models.ForeignKey('auth.User', related_name='posts', on_delete=models.CASCADE)

    class Meta:
        ordering = ('-pub_time',)


class Tag(models.Model):
    name = models.CharField(max_length=50)

作者model 使用 Django 的 User model, 便利驗(yàn)證和權(quán)限管理

構(gòu)建 Serializer

Serializer 是 rest framework 非常重要的一個(gè)部分
在 Django 中一般是 Model 和 View 之間交互,由 View 處理請(qǐng)求,把數(shù)據(jù)傳給Model, View 展現(xiàn)從 Model 得到的數(shù)據(jù)
而在 rest framework 中 Serializer 就相當(dāng)于 Model 和 View 的中間處理,將從 Model 中得到的數(shù)據(jù)序列化后交給 View, 將從 View 中得到的數(shù)據(jù)反序列化后交給 Model

新建 serializer.py 使用 HyperlinkedModelSerializer 構(gòu)建 Serializer:

from django.contrib.auth.models import User
from restAPI.models import Post, Tag


class PostSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Post
        fields = ('url', 'id', 'title', 'pub_time', 'author', 'body', 'tags')


class TagSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Tag
        fields = ('url', 'id', 'name', 'posts')


class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = ('url', 'id', 'username', 'posts')

HyperlinkedModelSerializer 默認(rèn)會(huì)為關(guān)系數(shù)據(jù)生成 url, 所以不用在 Tag 和 User中聲明 fields 中的 'posts'

構(gòu)建 View

設(shè)置權(quán)限, 新建 permission.py:

from rest_framework import permissions


class IsAuthorOrReadOnly(permissions.BasePermission):
    """
    只允許作者修改但允許所有人讀的權(quán)限設(shè)置
    """

    def has_object_permission(self, request, view, obj):
        # 所有用戶都允許讀取,所以安全的http方法會(huì)直接放行
        # SAFE_METHODS = ('GET', 'HEAD', 'OPTIONS')
        if request.method in permissions.SAFE_METHODS:
            return True

        # 寫入權(quán)限需要作者本人
        return obj.author == request.user

用 viewsets 構(gòu)建 View:

from rest_framework import viewsets, permissions, mixins
from django.contrib.auth.models import User
from restAPI.models import Post, Tag
from restAPI.serializers import PostSerializer, TagSerializer, UserSerializer
from restAPI.permissions import IsAuthorOrReadOnly


class PostViewSet(viewsets.ModelViewSet):
    """
    處理 /api/posts/ GET POST , 處理 /api/post/<pk>/ GET PUT PATCH DELETE
    """
    queryset = Post.objects.all()
    serializer_class = PostSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsAuthorOrReadOnly)
    
    def perform_create(self, serializer):
    """
    重寫 perform_create
    user 信息不在 request.data 中, 在保存時(shí)加入 user 信息
    """
    serializer.save(author=self.request.user)
    

class TagViewSet(mixins.CreateModelMixin,
                 mixins.ListModelMixin,
                 mixins.RetrieveModelMixin,
                 viewsets.GenericViewSet):
    """
    處理 /api/tags/ GET POST, 處理 /api/tags/<pk>/ GET
    """
    queryset = Tag.objects.all()
    serializer_class = TagSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,)


class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    處理 /api/users/ GET, 處理 /api/users/<pk>/ GET
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

ModelViewSet 通過 create() 中 get_serializer(data=request.data) 將數(shù)據(jù)傳給 serializer, 但是 user 信息并不在 request.data 中,而是作為 request 的一個(gè)屬性,
所以通過重寫 perform_create() 在保存時(shí)添加 user

構(gòu)建 urls

因?yàn)槭褂玫氖?viewsets 所有通過 router 構(gòu)建 urls 非常簡單:
項(xiàng)目 urls:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('restAPI.urls'))
]

app urls:

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from restAPI.views import PostViewSet, TagViewSet, UserViewSet

router = DefaultRouter()
router.register(r'posts', PostViewSet)
router.register(r'tags', TagViewSet)
router.register(r'users', UserViewSet)

urlpatterns = [
    path('', include(router.urls)),
    path('api-auth/', include('rest_framework.urls')),
]

include(router.urls) 會(huì)幫我們直接生成好

  • /api/posts/
  • /api/posts/<pk>/
  • /api/users/
  • /api/users/<pk>/
  • /api/tags/
  • /api/tags/<pk>/

結(jié)尾

到此基礎(chǔ)的 API 就構(gòu)建完了, 但是還留有一些問題:

  • GET /api/posts/ 得到的序列中的 'body' 是全部的信息, 我們?cè)讷@取 posts 列表的時(shí)候不需要那么完整的信息, 導(dǎo)致流量浪費(fèi), 在tag author中只有鏈接,信息太少
  • GET /api/tags/ posts 只有鏈接, 信息太少

這些會(huì)在下一篇中解決

其它:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 版本 : Django==2.0.1 djangorestframework==3.7.7 Github地址 其它...
    Jimzjy閱讀 2,027評(píng)論 0 4
  • 前言 本文標(biāo)題為實(shí)戰(zhàn),那么希望你已經(jīng)搭建好了環(huán)境。如果沒有,請(qǐng)參考官方文檔進(jìn)行環(huán)境搭建: 官方教程 通過學(xué)習(xí)這個(gè)例...
    CSU_IceLee閱讀 5,301評(píng)論 6 12
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,111評(píng)論 25 709
  • Django: csrf防御機(jī)制 csrf攻擊過程 1.用戶C打開瀏覽器,訪問受信任網(wǎng)站A,輸入用戶名和密碼請(qǐng)求登...
    lijun_m閱讀 1,151評(píng)論 0 0
  • 從前從前,有個(gè)人出生在大別山腹地,那里是我們口中所說的貧困山區(qū)。 幸運(yùn)很小就起早貪黑開始跟著父母勞作了,那時(shí),他才...
    粥七閱讀 261評(píng)論 0 0

友情鏈接更多精彩內(nèi)容