Django REST实现步骤

安装django及djangorestframework

pip install django
pip install djangorestframework
(注:本文环境python2.7.9, django 1.9.2, djangorestframework 3.3.3)

创建django rest project及app

与创建django项目方法一样

修改setting.py

INSTALLED_APPS添加rest_framework
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    ...
]
添加rest全局配置REST_FRAMEWORK
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',),
    'PAGE_SIZE': 10
}

添加自己的model

models.py文件中定义question model:
class Question(mongoengine.document.Document):
    question = mongoengine.fields.StringField(max_length = 10240, required = True)
    answer = mongoengine.fields.BooleanField(required = True)
    reason = mongoengine.fields.StringField(max_length = 1024)
    meta = {"db_alias": "wdbk", 'clooection': 'question'}

定义序列化类

新建serializers.py文件,定义序列化类,有三种方法:

(1) 继承于rest_framework.serializers.Serializer

class QuestionSerializer(serializers.Serializer):
    def create(self, validated_data):
        return Question.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.question = validated_data.get('question', instance.question)
        instance.answer = validated_data.get('answer', instance.answer)
        instance.reason = validated_data.get('reason', instance.reason)
        instance.save()
        return instance

(2) 继承 于rest_framework.serializers.ModelSerializer
class QuestionSerializer(<span style="font-family: Arial, Helvetica, sans-serif;">serializers.ModelSerializer</span>):
    class Meta:
        model = Question
        fields = ('question', 'answer', 'reason')
 
(3) 在视图中自己实现序列化

定义REST视图

有以下几种方法实现rest视图:
(1) 函数视图
自定义函数,使用api_view装饰器,在函数内部处理GET、POST等请求
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from models import Question
from serializers import QuestionSerializer

@api_view(['GET', 'POST'])
def question_list(request):
    if request.method == 'GET':
        questions = Question.objects.all()
        serializer = QuestionSerializer(questions, many=True)
        return Response(serializer.data)

    elif request.method == 'POST':
        serializer = QuestionSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
然后在urls.py中加入视图函数即可
(2) 基于类的视图
定义类继承于APIView,并实现get, post等方法
from models import Question
from serializers import QuestionSerializer
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status


class QuestionList(APIView):
    def get(self, request, format=None):
        questions = Question.objects.all()
        serializer = QuestionSerializer(questions, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = QuestionSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
在urls.py中添加视图类
urlpatterns += [
    url(r'^questions/$', views.QuestionList.as_view()),
]
(3)使用ViewSet
下面是我的ViewSet
from models import Question
from permission import IsOwnerOrReadOnly
from rest_framework.response import Response
from rest_framework import status

class QuestionViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list`, `create`, `retrieve`, `update` and `destroy` actions.
    Additionally we also provide an extra `initialization` and `random` action.
    """
    queryset = Question.objects.all()
    serializer_class = QuestionSerializer
    #permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
    #                      IsOwnerOrReadOnly,)

    @list_route()
    def initialization(self, request):
        try:
            excel = xlrd.open_workbook(settings.STATIC_ROOT + '/data/question.xls')
            sheet_question = excel.sheet_by_name('question')

        except Exception, e:
            return Response(data={'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        try:
            Question.objects().delete()
            for i in range(1, sheet_question.nrows):
                values = sheet_question.row_values(i)

                c = Question.objects(question=values[0])
                c.update(upsert = True,
                         set__question = values[0],
                         set__answer = bool(values[1]),
                         set__reason = values[2])

        except Exception, e:
            return Response(data={'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

        return Response(status=status.HTTP_201_CREATED)

    def get_object(self):
        pk = self.kwargs.get('pk')
        question = Question.objects(question=pk)
        #if question:
        return question[0]

    @list_route()
    def random(self, request):
        total = Question.objects.count()

        # 随机生成index
        randimskip = random.randint(1, total-1)

        # 查询问题
        questions = Question.objects.skip(randimskip).limit(20)
        serializer = self.get_serializer(questions, many=True)
        return Response(serializer.data)

上面的viewset中,有两个函数使用的@list_router装饰器,其表示这是用户自定义的额外的方法。因为有时候viewset自动生成的list, create, retrive, update, delete等方法不能满足我们的需要,比如需要随机查询数据库中的20条记录。在django debug输出中可以看到自定义方法的rest资源路径:

Using the URLconf defined in web.urls, Django tried these URL patterns, in this order:
^static/(?P<path>.*)$
^admin/
^rest/ ^ ^$ [name='api-root']
^rest/ ^ ^\.(?P<format>[a-z0-9]+)/?$ [name='api-root']
^rest/ ^ ^questions/$ [name='question-list']
^rest/ ^ ^questions\.(?P<format>[a-z0-9]+)/?$ [name='question-list']
^rest/ ^ ^questions/initialization/$ [name='question-initialization']
^rest/ ^ ^questions/initialization\.(?P<format>[a-z0-9]+)/?$ [name='question-initialization']
^rest/ ^ ^questions/random/$ [name='question-random']
^rest/ ^ ^questions/random\.(?P<format>[a-z0-9]+)/?$ [name='question-random']
^rest/ ^ ^questions/(?P<pk>[^/.]+)/$ [name='question-detail']
^rest/ ^ ^questions/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='question-detail']
^rest/ ^api-auth/


路由

在urls.py中添加如下代码:
from views import QuestionViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
# need to set base_name,otherwise will report:AttributeError: 'QuerySet' object has no attribute 'model'
router.register(r'questions', QuestionViewSet, r'question')

urlpatterns = [
    ...
    url(r'^', include(router.urls)),
 ]


REST安全认证

客户端有三种认证方式 BasicAuthentication、SessionAuthentication、TokenAuthentication
需要在setting.py中配置默认的认证类:
REST_FRAMEWORK = {
    # three auth way: session,basic,token
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',),
    'PAGE_SIZE': 10
}
具体可以参考 http://www.django-rest-framework.org/api-guide/authentication/#authentication
如果要使用djangorestframe提供的认证登录界面,需要在urlpatterns中添加:
urlpatterns = [
    ...
    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
]

monodb + djangorestframework

为了在djangorestframework中使用mongodb, 需要mongoengine和django-rest-framework-mongoengine
pip install mongoengine
pip install django-rest-framework-mongoengine
序列化类这样写
# -*- coding: utf-8 -*-
from rest_framework_mongoengine.serializers import DocumentSerializer
from models import *


class QuestionSerializer(DocumentSerializer):
    """
    使用ModelSerializer实现序列化
    """
    class Meta:
        model = Question
        fields = ('question', 'answer', 'reason')
        #depth = 2

    def create(self, validated_data):
        return Question.objects.create(**validated_data)

    def update(self, instance, validated_data):
        instance.question = validated_data.get('question', instance.question)
        instance.answer = validated_data.get('answer', instance.answer)
        instance.reason = validated_data.get('reason', instance.reason)
        instance.save()
        return instance
当然最笨的方法就是不使用mongoengine,利用pymongo自己封装model,并且不使用viewset实现视图

发布了40 篇原创文章 · 获赞 19 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/dogpig945/article/details/51361536