django rest framework实战

前言

本文标题为实战,那么希望你已经搭建好了环境。如果没有,请参考官方文档进行环境搭建:

官方教程

通过学习这个例子,你可以学到:

  1. 如何使用django rest framework去实现RESTful api
  2. 学会如何进行权限控制

希望对rest framework已经有了一定的了解,至少要知道serializers的作用,还有Response等等,基础知识还是要有的。

实战内容

我们实战的内容是,搭建一个博客应用,提供注册,登录功能。

所有用户都可以发表博客。

实现博客的创建者可以对自己的博客进行修改,删除等操作。

非创建者只能进行浏览。

思路

在登录的时候,将用户的id保存到request.session中,当用户修改博客或者是删除博客的时候,进行比对。所以权限管理主要是permissions.py这个文件的编写,之后再在views.py中进行设置权限即可。

开始

  1. 新建一个project:

    django-admin.py startproject rest

  2. 新建一个app:

    python manage startapp blog

  3. 在blog的models中,建立我们需要的model:

    class User(models.Model):
        username = models.CharField(max_length=20,null=False)
        password = models.CharField(max_length=20,null=False)
        name = models.CharField(max_length=10,null=False) #名称
    
    class Blog(models.Model):
        title = models.CharField(max_length=50,null=False)
        body = models.TextField()
        owner = models.ForeignKey(User) #博客的创建者
        
        def __str__(self):
            return self.title
    
  4. 在blog目录下新建一个serializers.py序列化文件:

    from rest_framework import serializers
    from blog.models import *
    
    class BlogSerializer(serializers.ModelSerializer):
        owner = serializers.ReadOnlyField(source='owner.name') #只读
        class Meta:
            exclude = []
            model = Blog
            fields = ('id', 'title', 'body', 'owner')
    
    #用于注册的时候返回json数据
    class UserRegisterSerializer(serializers.ModelSerializer):
        class Meta:
            exclude = []
            model = User
            field = ('id', 'username', 'name')
    
    class UserSerializer(serializers.ModelSerializer):
        blog_set = serializers.PrimaryKeyRelatedField(many=True, queryset=Blog.objects.all())
        class Meta:
            exclude = []
            model = User
            field = ('id', 'username', 'blog_set')
    
  5. 在blog目录下新建一个权限文件:permissions.py
    当用户登录之后,我们会在requests.session中加入用户的id,所以我们用id作为权限判断的依据:

#coding=utf-8
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):

    def has_permission(self, request, view):
        if request.method in permissions.SAFE_METHODS:
            return True
        return request.session.get('user_id') is not None

    def has_object_permission(self, request, view, blog):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True
        return blog.owner.id == request.session.get('user_id')
  1. 在views.py中,我们加入下列代码:

    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
    
    from django.shortcuts import render
    
    # Create your views here.
    from rest_framework import viewsets
    from rest_framework.permissions import AllowAny
    from rest_framework.response import Response
    from rest_framework.status import HTTP_200_OK, HTTP_400_BAD_REQUEST
    from rest_framework.views import APIView
    
    from blog.permissions import IsOwnerOrReadOnly
    from blog.serializers import *
    
    #用于登录
    class UserLoginAPIView(APIView):
        queryset = User.objects.all()
        serializer_class = UserSerializer
        permission_classes = (AllowAny,)
    
        def post(self, request, format=None):
            data = request.data
            username = data.get('username')
            password = data.get('password')
            user = User.objects.get(username__exact=username)
            if user.password == password:
                serializer = UserSerializer(user)
                new_data = serializer.data
                # 记忆已登录用户
                self.request.session['user_id'] = user.id
                return Response(new_data, status=HTTP_200_OK)
            return Response('password error', HTTP_400_BAD_REQUEST)
    
    #用于注册
    class UserRegisterAPIView(APIView):
        queryset = User.objects.all()
        serializer_class = UserRegisterSerializer
        permission_classes = (AllowAny,)
    
        def post(self, request, format=None):
            data = request.data
            username = data.get('username')
            if User.objects.filter(username__exact=username):
                return Response("用户名已存在",HTTP_400_BAD_REQUEST)
            serializer = UserRegisterSerializer(data=data)
            if serializer.is_valid(raise_exception=True):
                serializer.save()
                return Response(serializer.data,status=HTTP_200_OK)
            return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
    
    #用于博客的增删改查  除了查看,其他都需要权限
    class BlogViewSet(viewsets.ModelViewSet):
        queryset = Blog.objects.all()
        serializer_class = BlogSerializer
        permission_classes = (IsOwnerOrReadOnly,)
    
        def perform_create(self, serializer):
            print self.request.user
            serializer.save(owner=User.objects.get(id=self.request.session.get('user_id')))
    
    class UserViewSet(viewsets.ModelViewSet):
        queryset = User.objects.all()
        serializer_class = UserSerializer
    
    

    这样,我们就实现了权限的控制,如果查看博客,那么不会有什么问题。如果要提交博客,或者是删除博客,都是需要用户登录的,而且删除需要用户本人。没有权限则会返回{"detail": "Authentication credentials were not provided."}

  2. 在rest的urls.py中,我们为我们的view设置路由:

    from django.conf.urls import url,include
    from django.contrib import admin
    from rest_framework import routers
    from blog.views import *
    router = routers.DefaultRouter()
    router.register(r'users',UserViewSet)
    router.register(r'blogs',BlogViewSet)
    
    urlpatterns = [
        url(r'^',include(router.urls)),
        url(r'^admin/', admin.site.urls),
        url(r'^register',UserRegisterAPIView.as_view()),
        url(r'^login',UserLoginAPIView.as_view()),
    ]
    
  3. 在settings.py中,加入一些代码:

    INSTALLED_APPS = [
     ...
     ...
        'rest_framework',#rest框架 
        'blog',#我们的app
    ]
    #add to your settings.py
    REST_FRAMEWORK = {
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.AllowAny',
        ],
        'PAGE_SIZE': 10
    }
    
  4. 建立数据库

python manage makemigrations

python manage migrate

到此为止,就全部完成了,接下来可以访问API了!

使用

为了方便提交json数据,我使用了一款名叫Postman的工具,是GoogleChrome的一款插件,建议你也安装一个。如果你不想安装,那么你可以使用命令行的httpie工具,安装:

$ pip install --upgrade pip setuptools

$ pip install --upgrade httpie
  1. 注册一个用户,向http://127.0.0.1:8000/register提交一个post请求,参数如图:

    注册.png

    对应的httpie命令:

    http --json POST http://127.0.0.1:8000/register username="ICELEE" password="mypass" name="icelee"
    

    返回结果如下:

    {
        "id": 3,
        "username": "ICELEE",
        "password": "mypass",
        "name": "ICE"
    }
    

    因为我已经注册了两个了,所以id为3

  2. 先不登录,直接提交一篇博客:


    提交博客.png

    对应httpie的命令:

    http --json POST http://127.0.0.1:8000/blogs/ title="第一篇博客" body="哎哟 不错哦"

    结果是:

    {
        "detail": "Authentication credentials were not provided."
    }
    
  3. 登录:


    登录.png

对应的httpie命令:
http --json POST http://127.0.0.1:8000/login/ username="ICELEE" password="mypass"

返回的结果:

{
    "id": 3,
    "blog_set": [],
    "username": "ICELEE",
    "password": "mypass",
    "name": "ICE"
}
  1. 像第2点一样,再次提交博客,返回结果:

    {
        "id": 5,
        "title": "ICELEE的博客",
        "body": "哎哟 不错哦",
        "owner": "ICE"
    }
    

你可以再创建一个用户,然后登录,试着删除上面的博客试试,估计你是没办法删除的,因为你不是博客的拥有者,这就是权限控制的作用啦~~~

有疑问的地方请留言给我。
github项目地址

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

推荐阅读更多精彩内容

  • Django: csrf防御机制 csrf攻击过程 1.用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登...
    lijun_m阅读 1,032评论 0 0
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • API Reference GenericAPIView This class extends REST fram...
    阳光小镇少爷阅读 2,515评论 0 1
  • 经过对django的初步学习,我们已经对后台的基本流程以及django的运作有了一定的了解,但是这还不足够,dja...
    coder_ben阅读 3,797评论 8 34
  • 一路到今天 几次重大的决定都是自己做的 这也就是走上修行之路的条件 修行是提升意识 拥有和平、慈悲、无条件的爱与被...
    丰盛富足的小帅哥阅读 446评论 0 1