前言
本文标题为实战,那么希望你已经搭建好了环境。如果没有,请参考官方文档进行环境搭建:
通过学习这个例子,你可以学到:
- 如何使用django rest framework去实现RESTful api
- 学会如何进行权限控制
希望对rest framework已经有了一定的了解,至少要知道serializers的作用,还有Response等等,基础知识还是要有的。
实战内容
我们实战的内容是,搭建一个博客应用,提供注册,登录功能。
所有用户都可以发表博客。
实现博客的创建者可以对自己的博客进行修改,删除等操作。
非创建者只能进行浏览。
思路
在登录的时候,将用户的id保存到request.session中,当用户修改博客或者是删除博客的时候,进行比对。所以权限管理主要是permissions.py这个文件的编写,之后再在views.py中进行设置权限即可。
开始
-
新建一个project:
django-admin.py startproject rest
-
新建一个app:
python manage startapp blog
-
在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
-
在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')
-
在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')
-
在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."}
-
在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()), ]
-
在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 }
-
建立数据库
python manage makemigrations
python manage migrate
到此为止,就全部完成了,接下来可以访问API了!
使用
为了方便提交json数据,我使用了一款名叫Postman的工具,是GoogleChrome的一款插件,建议你也安装一个。如果你不想安装,那么你可以使用命令行的httpie工具,安装:
$ pip install --upgrade pip setuptools
$ pip install --upgrade httpie
-
注册一个用户,向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
-
先不登录,直接提交一篇博客:
提交博客.png
对应httpie的命令:
http --json POST http://127.0.0.1:8000/blogs/ title="第一篇博客" body="哎哟 不错哦"
结果是:
{ "detail": "Authentication credentials were not provided." }
-
登录:
登录.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"
}
-
像第2点一样,再次提交博客,返回结果:
{ "id": 5, "title": "ICELEE的博客", "body": "哎哟 不错哦", "owner": "ICE" }
你可以再创建一个用户,然后登录,试着删除上面的博客试试,估计你是没办法删除的,因为你不是博客的拥有者,这就是权限控制的作用啦~~~
有疑问的地方请留言给我。
github项目地址
网友评论