Django restframework 初识

Django restframework安装:

pip install djangorestframework

将django restframework注册到项目中:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'api.apps.ApiConfig',
]

在原生django中我们通过不能路由实现增删改查,例如这样:

http://127.0.0.1:8000/info/get/
http://127.0.0.1:8000/info/add/
http://127.0.0.1:8000/info/update/
http://127.0.0.1:8000/info/delete/

然后在views中定义不同的视图函数来处理请求。而Django restframework只需要一条路由,通过不同的请求方法实现前后端分离,主要的方法为:

http://127.0.0.1:8000/info/
    get,获取数据
    post,添加
    put,更新
    delete,删除

在原生django中我们可以通过CBV模式实现类似的功能,事实上django restframework的类视图正是基于django进行的开发,定制,所以可以看到很多地方它们是相似的。

urls.py

from django.conf.urls import url
from django.contrib import admin
from api import views

urlpatterns = [
    url(r'^drf/info/', views.DrfInfoView.as_view()),
]

views.py

from rest_framework.views import APIView
from rest_framework.response import Response

class DrfInfoView(APIView):

    def get(self,request,*args,**kwargs):
        data = [
            {'id': 1, 'title': '震惊了...王阳居然...', 'content': '...'},
            {'id': 2, 'title': '震惊了...王阳居然...', 'content': '...'},
            {'id': 3, 'title': '震惊了...王阳居然...', 'content': '...'},
            {'id': 4, 'title': '震惊了...王阳居然...', 'content': '...'},
        ]
        return Response(data)

models.py

from django.db import models

# Create your models here.

class Category(models.Model):
    """
    文章分类
    """
    name = models.CharField(verbose_name='分类',max_length=32)


class Article(models.Model):
    """
    文章表
    """
    status_choices = (
        (1, '发表'),
        (2, '删除'),
    )
    status = models.IntegerField(verbose_name='状态', choices=status_choices, default=1)
    title = models.CharField(verbose_name='标题',max_length=32)
    summary = models.CharField(verbose_name='简介',max_length=255)
    content = models.TextField(verbose_name='文章内容')
    category = models.ForeignKey(verbose_name='分类',to='Category')
    tag = models.ManyToManyField(verbose_name='标签', to='Tag', null=True, blank=True)

class Tag(models.Model):
    """标签"""
    title = models.CharField(verbose_name='标签',max_length=32)

django restframework发送的均为json格式数据,所拟需要对数据进行处理,这里用到了django内置的model_to_dict()方法

from django.conf.urls import url
from django.contrib import admin
from api import views
urlpatterns = [
    url(r'^drf/category/$', views.DrfCategoryView.as_view()),
    url(r'^drf/category/(?P<pk>\d+)/$', views.DrfCategoryView.as_view()),
]
from api import models
from django.forms.models import model_to_dict
class DrfCategoryView(APIView):
    def get(self,request,*args,**kwargs):
        """获取所有文章分类/单个文章分类"""
        pk = kwargs.get('pk')
        if not pk:
            queryset = models.Category.objects.all().values('id','name')
            data_list = list(queryset)
            return Response(data_list)
        else:
            category_object = models.Category.objects.filter(id=pk).first()
            data = model_to_dict(category_object)
            return Response(data)

    def post(self,request,*args,**kwargs):
        """增加一条分类信息"""
        models.Category.objects.create(**request.data)
        return Response('成功')

事实上,序列化的事情django restframework已经帮我们做好了,只需要引入并使用即可

我们写一个serializer.py文件

可以看到其中category是article的外键,这里为了查到category并显示其对应的中文名,我们用到了

 category = serializers.CharField(source='category.name')
class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = '__all__'

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        # fields = ['pk', 'title']
        fields = '__all__'


class ArticleSerializer(serializers.ModelSerializer):
    # 指定外键显示的字段来源
    category = serializers.CharField(source='category.name')
    tag = TagSerializer(many=True)

    class Meta:
        model = Article
        fields = "__all__"

 

另一种显示外键 字段的方法是:

class ArticleSerializer(serializers.ModelSerializer):
    category = serializers.SerializerMethodField()

    class Meta:
        model = Article
        fields = "__all__"

    def get_category(self, obj):
        return obj.category.name

这里的get_category是固定写法,get_fieldname.同样的道理,对于choiceField,也有类似的处理:

status = serializers.CharField(source='get_status_display')
def get_status(self,obj):
    return obj.get_status_display()

注意两者的写法区别,前者不加括号(django restframework会自动处理),后者是要加括号的,

我们看看在使用serizlizer之后的写法:

class DrfCategoryView(APIView):

    def get(self, request, *args, **kwargs):
        # 查
        id = kwargs.get('id')
        if id:
            category_obj = Category.objects.filter(id=id).first()
            ser = CategorySerializer(instance=category_obj, many=False)
            return Response(ser.data)
        category_objs = Category.objects.all()
        ser = CategorySerializer(instance=category_objs, many=True)
        return Response(ser.data)

    def post(self, request, *args, **kwargs):
        # 增加
        ser = CategorySerializer(data=request.data)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        return Response(ser.errors)

    def put(self, request, *args, **kwargs):
        id = kwargs.get('id')
        category_obj = Category.objects.filter(id=id).first()
        ser = CategorySerializer(instance=category_obj, many=True)
        if ser.is_valid():
            ser.save()
            return Response(ser.data)
        return Response(ser.errors)

    def delete(self, request, *args, **kwargs):
        id = kwargs.get('id')
        category_obj = Category.objects.filter(id=id).first()
        category_obj.delete()
        return Response('delete finish')

可以看到serializer类似于原生django中的form,也能对数据进行校验。当有多条数据时,需要添加many=True,默认情况下为False,序列化后的数据被保存在data这个属性中,类似于cleaned_data.

补充:局部更新数据,比如只更新某个字段,而其它字段的值都没有更新时,在django中是可以指定update_fields=['name',],在rest framework中则有两点要注意:一是使用patch方法,二是加partial=True

def patch(self, request, *args, **kwargs):
    pk = kwargs.get('pk')
    article_obj = Article.objects.filter(id=pk).first()
    ser = serializer.ArticleSerializer(instance=article_obj, data=request.data, partial=True)
    if ser.is_valid():
        ser.save()
        return Response(ser.data)
    return Response(ser.errors)

 

上一篇:pip is configured with locations that require TLS/SSL

下一篇:Django restframework 分页