Django REST framework

RESTful规范

你的项目接口是按照RESTful规范写的,那么它就是RESTful API。

设计指南:

	用HTTP协议的四个请求方法表示四个动作。

	GET:查询/获取资源

	POST:创建资源

	PUT:更新

	DELETE:删除

	十个设计规范:

		Https

		版本号

		api

		URL尽量不要用动词

		错误提示

		状态码

			1xx

			2xx

			3xx

			4xx

			502:网关不可用

			503:服务不可用

			504:网关超时

			505:版本不支持

		超链接表示表的关系

		过滤信息

		分页

浏览器的同源策略

什么是同源:

域名/ip + 端口 + 协议

http协议默认端口:80

https协议默认端口:443

浏览器对于非同源的请求会拒绝接受响应信息。

前后端分离的项目一般都会涉及到跨域问题

JSONP跨域(之前的解决方案)

不足:

只能GET请求

前端和后端都要支持

原理:

利用的就是浏览器对加载静态资源不做限制,比如<script src="跨域的地址"></script>

jQuery版JSONP

$.getJSON("http://127.0.0.1:8000/index/?callback=?", function(res){
    console.log(res);
})

CORS跨域

简单请求和非简单请求

简单请求同时满足两大类条件:

1请求方法:

	HEAD、GET、POST

2.请求头

	Accept

	Accept-Language

	Content-Language

	Last-Event-ID

	Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

如果发送的是PUT或DELETE请求就是费简单请求

再比如发送的是 Content-Type:application/json也是非简单请求

简单请求的处理方案:

在响应头加一个Access-Control-Allow-Origin *  --》 允许任何源给我发跨域请求

在响应头加一个Access-Control-Allow-Origin 127.0.0.1:8000  --》只允许  127.0.0.1:8000 给我发跨域请求

非简单请求:

浏览器会提前发一个 OPTIONS的预检请求

在响应头加一个Access-Control-Allow-Methods:'PUT, DELETE'  --》允许浏览器给我发PUT和DELETE的跨域请求

在响应头加一个Access-Control-Allow-Headers: 'Content-Type'  --》 允许浏览器给我发请求头中修改Content-Type字段

使用django-cors-headers包

pip install django-cors-headers

在中间件中注册

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',  # 添加中间件
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    # 'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

在Django的settings.py中配置:

CORS_ORIGIN_ALLOW_ALL = True  # 允许任何网站都来发跨域请求

配置可跨域访问的白名单:

CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
    # '<YOUR_DOMAIN>[:PORT]',
    '127.0.0.1:8080'
)

Django REST framework

1.安装:

pip install djangorestframework

2.使用:

  1. 注册app (不是必须)注册之后能够在页面的视图中看到
    INSTALLED_APPS = [
    #…
    ‘corsheaders’,
    ‘rest_framework’
    ]
    常规的django操作
    1创建超级用户
    >python manage.py createsuperuser
    >Username (leave blank to use ‘administrator’): root
    >Email address:直接回车表示不填写
    >Password:密码
    >Password (again):密码
    Superuser created successfully.
    2修改时区和后台显示语言
    # LANGUAGE_CODE = ‘en-us’
    LANGUAGE_CODE = ‘zh-hans’

    # TIME_ZONE = 'UTC'
    TIME_ZONE = 'Asia/Shanghai'
    

    3.注册model到admin中 以便于后台管理
    from django.contrib import admin
    from myJsonApi import models

    admin.site.register(models.Book)
    admin.site.register(models.Author)
    admin.site.register(models.Publisher)
    
    1. 导入APIView from rest_framewor.views import APIView, CBV继承它
      1. 1 自己写一个序列化的工具类 BookSerializer
        from rest_framework import serializers
        from myJsonApi import models

        class AuthorSerializers(serializers.Serializer):
            id = serializers.IntegerField()
            name = serializers.CharField(max_length=32)
        
        
        class PublisherSerializers(serializers.Serializer):
            id = serializers.IntegerField()
            name = serializers.CharField(max_length=32)
        
        
        # 相当于django的form和ModelForm
        class BookSerializers(serializers.Serializer):
            # required=False指的是不是必填项(保存数据时数据库自动生成id的时候)
            id = serializers.IntegerField(required=False)
            # 对长度进行校验
            title = serializers.CharField(max_length=32)
            # 等号前面填写的就是数据库中写的字段名
            pub_date = serializers.DateField()
            # sourse="get_category_display"是拿到数据库中存的展示的值
            # 例如 CHOICES为1代表的值时Python
            #  CHOICES = ((1, 'Python'), (2, 'Go'), (3, 'Linux'))
            category = serializers.CharField(source="get_category_display", read_only=True)
            post_category = serializers.CharField(write_only=True)
            # read_only=True是给前端发数据的时候用的
            # 调用前面定义好的类来处理出版社,(外键)
            publisher = PublisherSerializers(read_only=True)
            post_publisher = serializers.IntegerField(write_only=True)
            # many=True,代表的是可以展示多个
            # 调用前面定义好的类来处理作者,(多对多字段)
            author = AuthorSerializers(many=True, read_only=True)
            # write_only = True是在后端收到前端数据的时候用的
            # 意味着前端传值的时候关键字变为自己定义的post_author
            # ListField可以传数组即多个值
            post_author = serializers.ListField(write_only=True)
        

        1.2 在视图中调用
        from rest_framework.views import APIView
        from rest_framework.response import Response
        from myJsonApi.Serializers import BookSerializers

        class BookList(APIView):
            def get(self, request):
                # 查询出数据
                books = models.Book.objects.all()
                # 进行序列化
                books_json = BookSerializers(books, many=True)
                # 返回json格式的数据
                return Response(books_json.data)
        

        post新增数据
        在BookSerializers中
        def create(self, validated_data):
        # validated_data是校验过的数据
        book_obj = models.Book.objects.create(
        title=validated_data.get(‘title’),
        pub_date=validated_data[‘pub_date’],
        category=validated_data[‘post_category’],
        publisher_id=validated_data[‘post_publisher’], # 1
        )
        book_obj.authors.set(validated_data[‘post_authors’])
        return book_obj
        在视图中class BookList(APIView):
        def post(self, request):
        # 获取数据(因为APIView对request进行增强,将数据赋值到了request.data)
        # 对数据进行有效性校验
        ser_obj = BookSerializers(data=request.data)
        if ser_obj.is_valid():
        # .save()# 调用的是BookSerializer类中的create方法,需要自己去实现
        # 拿到序列化的数据去数据库创建新记录
        ser_obj.save()
        else:
        # 校验失败则返回错误原因
        return Response(ser_obj.errors)
        return Response(“ok”)

对单本书的增删改查

在ModelSerializers中

"""
专门用来做序列化的工具类
"""

from rest_framework import serializers
from bms import models


class PublisherSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField()


class AuthorSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField()


class BookModelSerializer(serializers.ModelSerializer):
    # SerializerMethodField 会自动去找 get_字段名 的方法执行
    category_info = serializers.SerializerMethodField(read_only=True)
    publisher_info = serializers.SerializerMethodField(read_only=True)
    authors_info = serializers.SerializerMethodField(read_only=True)

    def get_category_info(self, book_obj):
        # obj ==》 当前被序列化的那个书籍对象
        return book_obj.get_category_display()

    def get_publisher_info(self, book_obj):
        # book_obj.pulisher  ==> 得到和我这本书关联的出版社对象

        # return {
        #     "id": book_obj.publiser.id,
        #     "name": book_obj.publiser.name
        # }
        # ser_obj = PublisherSerializer(book_obj.publisher)
        # return ser_obj.data
        return PublisherSerializer(book_obj.publisher).data

    def get_authors_info(self, book_obj):
         # 这里的.all()和 many=True是指有多个作者的时候这样写
        return AuthorSerializer(book_obj.authors.all(), many=True).data

    class Meta:
        model = models.Book
        fields = "__all__"
        # depth = 1  # 所有有关系的字段都变成 read_only
        # exclude = []  # 排除某个字段
        extra_kwargs = {  # 每个字段的一些额外参数
            'publisher': {'write_only': True},
            'authors': {'write_only': True},
            'category': {'write_only': True},
        }

在视图中使用BookModelSerializer

from 你的app.你的py文件写的名字 import BookModelSerializer

class BookDetailView(APIView):
    """这是书籍详情相关的接口 支持:GET/PUT/DELETE"""
    def get(self, request, pk):
        """获取具体某本书的信息"""
        # 1. 根据pk去查询具体的那本书籍对象
        book_obj = models.Book.objects.filter(pk=pk).first()
        if book_obj:
            # 2. 将书籍对象 序列化成 json格式的数据
            ser_obj = BookModelSerializer(book_obj)
            # 3. 返回响应
            return Response(ser_obj.data)
        else:
            return Response("无效的书籍id")

    def put(self, request, pk):
        """修改具体某一本书"""
        # 1. 根据pk去查询具体的那本书籍对象
        book_obj = models.Book.objects.filter(pk=pk).first()
        if book_obj:
            # 2. 获取用户 发送过来的数据并且更新对象
            ser_obj = BookModelSerializer(instance=book_obj, data=request.data, partial=True)  # form组件中也有类似的实现
            if ser_obj.is_valid():
                # 3. 保存并返回修改后的数据
                ser_obj.save()
                return Response(ser_obj.data)
            else:
                return Response(ser_obj.errors)
        else:
            return Response("无效的书籍id")

    def delete(self, request, pk):
        """删除具体某一本书"""
        # 1. 根据pk去查询具体的那本书籍对象
        book_obj = models.Book.objects.filter(pk=pk)
        if book_obj:
            # 删除书籍对象
            book_obj.delete()
            return Response("删除成功")
        else:
            return Response("无效的书籍id")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值