Django REST framework学习笔记

Stella981
• 阅读 835

文章目录

我的网站: https://pythoneers.cn

1. API接口开发
1.1 获取数据的接口

获取所有的字段:

from rest_framework import views, serializers, response
from .. import models

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.User
        fields = "__all__"

class User(views.APIView):
    def get(self, request):
        qs = models.User.objects.all()
        serializer = UserSerializer(qs, many=True)
        return response.Response({
   
   
   
            'status': 0,
            'data': serializer.data
        })

Django REST framework学习笔记
获取部分字段:

from rest_framework import views, serializers, response
from .. import models

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.User
        fields = ('id', 'name') # 只需要修改这里

class User(views.APIView):
    def get(self, request):
        qs = models.User.objects.all()
        serializer = UserSerializer(qs, many=True)
        return response.Response({
   
   
   
            'status': 0,
            'data': serializer.data
        })

Django REST framework学习笔记
获取单条数据:

from rest_framework import views, serializers, response
from .. import models

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.User
        fields = ('id', 'name')

class User(views.APIView):
    def get(self, request):
        qs = models.User.objects.all()
        serializer = UserSerializer(qs.first(), many=False)  # 默认是False,修改这里
        return response.Response({
   
   
   
            'status': 0,
            'data': serializer.data
        })

Django REST framework学习笔记

1.2 添加数据的接口

添加数据:

from rest_framework import views, serializers, response
from .. import models

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.User
        fields = "__all__"

class User(views.APIView):
    def post(self, request):
        serializer = UserSerializer(data=request.data)
        result = {
   
   
   'status': 0, 'data': None}
        if serializer.is_valid():
            instance = serializer.save()
            result['data'] = instance.pk
            return response.Response(result)
        else:
            result['status'] = 1
            result['data'] = serializer.errors
        return result

Django REST framework学习笔记

1.3 更新数据的接口

更新数据的接口:

from rest_framework import views, serializers, response
from .. import models

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.User
        fields = "__all__"
        
class UserDetail(views.APIView):
    def put(self, request, pk):
        instance = models.User.objects.filter(pk=pk).first()
        result = {
   
   
   'status': 0, 'data': None}
        if not instance:
            result['status'] = 1
            result['data'] = '数据不存在!'
        else:
            # 如果没有传入instance,默认是None,表示添加数据而不是更新数据
            serializer = UserSerializer(instance=instance, data=request.data)
            if serializer.is_valid():
                instance = serializer.save()
                result['data'] = instance.pk
            else:
                result['status'] = 1
                result['data'] = serializer.errors
        return response.Response(result)

没有查询到要更新的数据:
Django REST framework学习笔记
更新数据成功:
Django REST framework学习笔记

1.4 删除数据的接口

删除数据的接口:

from rest_framework import views, serializers, response
from .. import models

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.User
        fields = "__all__"
        
class UserDetail(views.APIView):
    def delete(self, request, pk):
        instance = models.User.objects.filter(pk=pk)
        result = {
   
   
   'status': 0, 'data': None}
        if not instance:
            result['status'] = 1
            result['data'] = '数据不存在,无法删除!'
        else:
            instance.delete()
            result['data'] = []
        return response.Response(result)

删除的数据不存在:
Django REST framework学习笔记
删除数据成功:
Django REST framework学习笔记

2. API字段的定制

表中的字段有时候是不能满足我们实际需要的,所以大多情况下我们需要 **加工从数据库中获取到的字段,以及扩展更多的字段**。也可能获取别的表的字段进行数据加工生成新字段,响应给前端让它做数据渲染。下面是对字段处理的几种方式:

2.1 别名字段

这种是最简单的,返回给客户端的字段和原字段的字段名不同,但是 **值相同**:

class UserSerializer(serializers.ModelSerializer):
    name = serializers.CharField(max_length=5, error_messages={
   
   
   'max_length': '字段太长!'})
    alias = serializers.CharField(source='name') # 注意这里source='name'

    class Meta:
        model = models.User
        fields = ('name', 'alias')
        
class User(views.APIView):
    def get(self, request):
        qs = models.User.objects.all()
        serializer = UserSerializer(qs, many=True)
        return response.Response({
   
   
   
            'status': 0,
            'data': serializer.data
        })

Django REST framework学习笔记

2.2 字段格式化

对从数据库中获取的日起进行格式化,数据库中格式是:2020-06-20 03:32:28.376772,格式化之后是:2020-06-20 03:32:28,

class UserSerializer(serializers.ModelSerializer):
    name = serializers.CharField(max_length=5, error_messages={
   
   
   'max_length': '字段太长!'})
    alias = serializers.CharField(source='name')
    register_date = serializers.DateTimeField(format='%Y-%m-%d %X') # 在这里进行的格式化

    class Meta:
        model = models.User
        fields = ('name', 'alias', 'register_date')

class User(views.APIView):
    def get(self, request):
        qs = models.User.objects.all()
        serializer = UserSerializer(qs, many=True)
        return response.Response({
   
   
   
            'status': 0,
            'data': serializer.data
        })

Django REST framework学习笔记

2.3 字段创建

字段别名的方式可以认为是创建新的字段,但是它还是依赖于原字段,不是真正意义上的创建新字段:

class UserSerializer(serializers.ModelSerializer):
    name = serializers.CharField(max_length=5, error_messages={
   
   
   'max_length': '字段太长!'})
    alias = serializers.CharField(source='name')
    register_date = serializers.DateTimeField(format='%Y-%m-%d %X')
    """
    创建新字段,自定义名字是id
    """
    # id = serializers.SerializerMethodField(method_name='get_id')  # 可以指定使用的方法名称
    id = serializers.SerializerMethodField()  # 可以不指定默认是:get_id,需要写get_id方法
    
    def get_id(self, instance):
        """
        :param instance: 查询的结果(直接写上instance就可以获取instance)
        :return:
        """
        return instance.pk

    class Meta:
        model = models.User
        fields = ('name', 'alias', 'register_date', 'id')
        
class User(views.APIView):
    def get(self, request):
        qs = models.User.objects.all()
        serializer = UserSerializer(qs, many=True)
        return response.Response({
   
   
   
            'status': 0,
            'data': serializer.data
        })

Django REST framework学习笔记

2.4 字段加工

一般情况下,网站的图片使用CDN加速,CDN可能来自不同的CDN服务提供商。如果要换CDN服务提供商,那么接口返回的所有图片链接都需要更新。如果我们对链接部分进行处理,让链接的域名部分可以独立出来,这样如果换提供商,直接修改域名就可以了,下面是个简单的示例:

class ImagePathField(serializers.Field):
    def __init__(self, domain=None, *args, **kwargs):
        self.domain = domain
        super(ImagePathField, self).__init__(*args, **kwargs)

    def to_representation(self, value):
        if not self.domain:
            self.domain = 'www.aistudies.com.cn'
        # return '{}' + '{}.png'.format(self.domain, value)
        return f'{self.domain}/{value}.jpg'

    def to_internal_value(self, data):
        return data

class UserSerializer(serializers.ModelSerializer):
    name = serializers.CharField(max_length=5, error_messages={
   
   
   'max_length': '字段太长!'})
    alias = serializers.CharField(source='name')
    register_date = serializers.DateTimeField(format='%Y-%m-%d %X')
    images = serializers.CharField()
    # 如果source=None,则返回给客户端的img是null
    img = ImagePathField(domain='www.baidu.com', source='images')

    def get_id(self, instance):
        """
        :param instance: 查询的结果(直接写上instance就可以获取instance)
        :return:
        """
        return instance.pk

    class Meta:
        model = models.User
        fields = ('name', 'alias', 'register_date', 'id', 'images', 'img')

class User(views.APIView):
    def get(self, request):
        qs = models.User.objects.all()
        serializer = UserSerializer(qs, many=True)
        return response.Response({
   
   
   
            'status': 0,
            'data': serializer.data
        })

Django REST framework学习笔记
只是作为例子使用了下,当然这里还是有很多问题的!

3. DRF认证
3.1 自定义认证

有些API不需要用户登录就可以访问,但是有些需要用户登录才可以访问。Django REST framework中内置认证组件,可以实现需要用户登录才可以访问API的功能。借助内置认证组件,可以方便地自定义认证规则:

models.py

from django.db import models

# Create your models here.
class User(models.Model):
    name = models.CharField(max_length=32, unique=True)
    pwd = models.CharField(max_length=64)
    user_type_choices = (
        (1, '普通用户'),
        (2, 'VIP'),
        (3, 'SVIP')
    )
    user_type = models.IntegerField(choices=user_type_choices)

class UserToken(models.Model):
    token = models.CharField(max_length=64)
    user = models.OneToOneField(to='User',on_delete=models.CASCADE)

Django REST framework学习笔记
写一些数据,用于登录认证测试:
Django REST framework学习笔记
setting.py

DATABASES = {
   
   
   
    'default': {
   
   
   
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'drftest',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': 'localhost',
        'PORT': '3306'
    },
    'mysql': {
   
   
   
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

views.py:

import hashlib, time
from rest_framework.views import APIView, exceptions
from .models import User, UserToken
from django.http import JsonResponse

# Create your views here.
def md5(name):
    obj = hashlib.md5(bytes(name, encoding='utf-8'))
    ctime = str(time.time())
    obj.update(bytes(ctime, encoding='utf-8'))
    return obj.hexdigest()

class Authenticate:
    def authenticate(self, request):
        token = request._request.GET.get('token')
        print(token)
        token_obj = UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败!')
        # 在rest framework内部会将整个两个字段赋值给request,共后续操作使用
        # 有三种返回值,None:表示不管;异常:没有通过认证;元组:返回下面两个元素,一个给request.use,一个给request.auth
        return (token_obj.user, token_obj)  # (request.user,request.auth)

    def authenticate_header(self, request):
        pass

class AuthView(APIView):
    def post(self, request, *args, **kwargs):
        """
        用户登录成功后,返回根据时间辍生成的token,每次登录的时间不同,每次生成的token也不同,都被记录到token表中用于与每次请求带着的token进行对比。如果对比成功,则认证成功,是允许访问的。
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        ret = {
   
   
   'code': 1000, 'msg': None}
        try:
            # 需要以form-data的方式提交
            name = request._request.POST.get('name')
            pwd = request._request.POST.get('pwd')
            instance = User.objects.filter(name=name, pwd=pwd).first()  # User object (1),
            print(type(instance))  # <class 'app.models.User'>,加不加all()结果一样
            print(instance)  # User object (1),加不加all()结果一样
            if not instance:
                ret['code'] = 1001
                ret['msg'] = '用户名或密码错误'
            else:
                token = md5(name=name)
                UserToken.objects.update_or_create(user=instance, defaults={
   
   
   'token': token})
                ret['token'] = token
        except Exception as e:
            ret['code'] = 1001
            ret['msg'] = '请求异常'
        return JsonResponse(ret)

class OrderView(APIView):
    # 列表中有写认证类则需要认证,使用自定义的Authenticate类来认证
    authentication_classes = [Authenticate, ]

    def get(self, request, *args, **kwargs):
        # request.user
        # request.auth
        self.dispatch
        order_dict = {
   
   
   
            1: {
   
   
   
                'name': "thanlon",
                'age': 24,
                'gender': '男',
            },
            2: {
   
   
   
                'name': "kiku",
                'age': 26,
                'gender': '女',
            },
        }
        # token = request._request.GET.get('token')
        ret = {
   
   
   'code': 1000, "msg": None, 'data': None}
        try:
            ret['data'] = order_dict
        except Exception as e:
            pass
        return JsonResponse(ret)

登录时生成的token:
Django REST framework学习笔记
用于用户登录成功生成token的类AuthView不需要认证,OrderView类需要认证,如果不带token访问这个接口会返回失败的认证:
Django REST framework学习笔记
带着这token来访问这个接口,**注意这里从url中获取的,要把token放在url上,不要放到请求头发送过去**。结果发现可以访问到请求的数据:
Django REST framework学习笔记
也可以放到请求头中发过去,认证类获取token的时候要到请求头中获取。

3.2 认证流程

想要更好地使用认证组件,不得不研究和学习下认证组件的实现原理:
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
认证可以加多个,一般不会使用到多个认证。列表中的认证类中从第一个开始,如果第一个认证没有做处理,返回None,则交给下一个认证处理:

import hashlib, time
from rest_framework.views import APIView, exceptions
from .models import User, UserToken
from django.http import JsonResponse

# Create your views here.
def md5(name):
    obj = hashlib.md5(bytes(name, encoding='utf-8'))
    ctime = str(time.time())
    obj.update(bytes(ctime, encoding='utf-8'))
    return obj.hexdigest()

class Authenticate:
    def authenticate(self, request):
        token = request._request.GET.get('token')
        print(token)
        token_obj = UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败!')
        # 在rest framework内部会将整个两个字段赋值给request,共后续操作使用
        return (token_obj.user, token_obj)  # (request.name,request.auth)

    def authenticate_header(self, request):
        pass

class FirstAuthenticate:
    def authenticate(self, request):
        pass

    def authenticate_header(self, request):
        pass

class AuthView(APIView):
    def post(self, request, *args, **kwargs):
        print(md5('thanlon'))
        ret = {
   
   
   'code': 1000, 'msg': None}
        try:
            # 需要以form-data的方式提交
            name = request._request.POST.get('name')
            pwd = request._request.POST.get('pwd')
            instance = User.objects.filter(name=name, pwd=pwd).first()  # User object (1),
            print(type(instance))  # <class 'app.models.User'>,加不加all()结果一样
            print(instance)  # User object (1),加不加all()结果一样
            if not instance:
                ret['code'] = 1001
                ret['msg'] = '用户名或密码错误'
            else:
                token = md5(name=name)
                UserToken.objects.update_or_create(user=instance, defaults={
   
   
   'token': token})
                ret['token'] = token
        except Exception as e:
            ret['code'] = 1001
            ret['msg'] = '请求异常'
        return JsonResponse(ret)

class OrderView(APIView):
    # 需要认证,使用自定义的Authenticate类来认证
    authentication_classes = [FirstAuthenticate, Authenticate, ]

    def get(self, request, *args, **kwargs):
        # request.name
        # request.auth
        self.dispatch
        order_dict = {
   
   
   
            1: {
   
   
   
                'name': "thanlon",
                'age': 24,
                'gender': '男',
            },
            2: {
   
   
   
                'name': "kiku",
                'age': 26,
                'gender': '女',
            },
        }
        # token = request._request.GET.get('token')
        ret = {
   
   
   'code': 1000, "msg": None, 'data': None}
        try:
            ret['data'] = order_dict
        except Exception as e:
            pass
        return JsonResponse(ret)

流程概述:

- dispatch
    - 封装request
        - 获取定义的认证类(全局或者局部),通过列表生成式创建对象
    - initial
        - perform_authentication
            request.user
                内部循环认证类执行authenticate方法
3.3 全局配置认证

如果我们不使用自己的认证类,默认使用Django REST framework的认证类,路径在配置文件中。源码中有体现:
Django REST framework学习笔记
Django REST framework学习笔记
加下来可以这样来配置全局的认证类。在app目录下创建用于存放认证类的 auth,py 文件(认证的类不要写在views中,否则可能引用出现问题),然后在 settings.py 的认证配置项指向这个文件:

settings.py:

REST_FRAMEWORK = {
   
   
   
    'DEFAULT_AUTHENTICATION_CLASSES': ['app.auth.FirstAuthenticate', 'app.auth.Authenticate', ]
}

auth.py:

from rest_framework.views import exceptions
from .models import UserToken

class FirstAuthenticate:
    def authenticate(self, request):
        pass

    def authenticate_header(self, request):
        pass


class Authenticate:
    def authenticate(self, request):
        token = request._request.GET.get('token')
        print(token)
        token_obj = UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户认证失败!')
        # 在rest framework内部会将整个两个字段赋值给request,共后续操作使用
        return (token_obj.user, token_obj)  # (request.name,request.auth)

    def authenticate_header(self, request):
        pass

这样配置之后全部请求的方法都需要认证,但是有些是需要认证的,比如登录的方法,也需要认证:
Django REST framework学习笔记
只需要在类中把authentication_classes设置为空列表即可:

class AuthView(APIView):
    authentication_classes = []

    def post(self, request, *args, **kwargs):
        print(md5('thanlon'))
        ret = {
   
   
   'code': 1000, 'msg': None}
        try:
            # 需要以form-data的方式提交
            name = request._request.POST.get('name')
            pwd = request._request.POST.get('pwd')
            instance = User.objects.filter(name=name, pwd=pwd).first()  # User object (1),
            print(type(instance))  # <class 'app.models.User'>,加不加all()结果一样
            print(instance)  # User object (1),加不加all()结果一样
            if not instance:
                ret['code'] = 1001
                ret['msg'] = '用户名或密码错误'
            else:
                token = md5(name=name)
                UserToken.objects.update_or_create(user=instance, defaults={
   
   
   'token': token})
                ret['token'] = token
        except Exception as e:
            ret['code'] = 1001
            ret['msg'] = '请求异常'
        return JsonResponse(ret)

正常访问,不需要认证:
Django REST framework学习笔记

3.4 匿名用户配置

可以根据源码,来配置匿名用户:
Django REST framework学习笔记
Django REST framework学习笔记
settings.py:

REST_FRAMEWORK = {
   
   
   
    # 'DEFAULT_AUTHENTICATION_CLASSES': ['app.auth.FirstAuthenticate', 'app.auth.Authenticate', ]
    'DEFAULT_AUTHENTICATION_CLASSES': ['app.auth.FirstAuthenticate', ],  # FirstAuthenticate中什么也没有做
    # 'UNAUTHENTICATED_USER': lambda x: '匿名用户',
    'UNAUTHENTICATED_USER': None,  # request.user = None,默认是AnonymousUser
    'UNAUTHENTICATED_TOKEN': None  # request.auth = None
}
3.5 内置基本认证

Django REST framework中内置了很多内部认证类,
Django REST framework学习笔记
导入这些认证类的方式:

from rest_framework.authentication import BaseAuthentication,BasicAuthentication, SessionAuthentication,TokenAuthentication, RemoteUserAuthentication

BaseAuthentication类有两种方法,所有的认证类必须继承这个类:

class BaseAuthentication:
    """
    All authentication classes should extend BaseAuthentication.
    """

    def authenticate(self, request):
        """
        Authenticate the request and return a two-tuple of (user, token).
        自定义认证操作的方法
        """
        raise NotImplementedError(".authenticate() must be overridden.")

    def authenticate_header(self, request):
        """
        Return a string to be used as the value of the `WWW-Authenticate`
        header in a `401 Unauthenticated` response, or `None` if the
        authentication scheme should return `403 Permission Denied` responses.
        认证失败之后给浏览器返回的响应头,
        """
        pass

自定义认证类的时候,**必须继承BaseAuthentication**,其它的认证类中BasicAuthentication是浏览器对用户名和密码进行base64加密,

HTTP_AUTHORIZATION:basic base64(用户名和密码)

然后放到请求头里面发送给服务端。服务端接收数据后进行处理,之后做一系列的校验:
Django REST framework学习笔记
剩下的认证则是基于Django的session和token等实现的认证。

4. DRF权限
4.1 权限的基本使用

对于不同的视图应该有不同的访问权限,下面是权限的基本使用:

permission.py:

class MyPermission1:
    def has_permission(self, request, view):
        # 超级用户可以访问
        if request.user.user_type != 3:
            return False
        return True


class MyPermission2:
    def has_permission(self, request, view):
        # 普通用户可以访问,超级用户不可以访问
        if request.user.user_type == 3:
            return False
        return True

views.py:

from rest_framework.views import APIView
from .models import User, UserToken
from django.http import JsonResponse
from utils.md5 import md5
from django.http import HttpResponse
from app import permission

class AuthView(APIView):
    authentication_classes = []

    def post(self, request, *args, **kwargs):
        ret = {
   
   
   'code': 1000, 'msg': None}
        try:
            # 需要以form-data的方式提交
            name = request._request.POST.get('name')
            pwd = request._request.POST.get('pwd')
            instance = User.objects.filter(name=name, pwd=pwd).first()  # User object (1),
            print(type(instance))  # <class 'app.models.User'>,加不加all()结果一样
            print(instance)  # User object (1),加不加all()结果一样
            if not instance:
                ret['code'] = 1001
                ret['msg'] = '用户名或密码错误'
            else:
                token = md5(name=name)
                UserToken.objects.update_or_create(user=instance, defaults={
   
   
   'token': token})
                ret['token'] = token
        except Exception as e:
            ret['code'] = 1001
            ret['msg'] = '请求异常'
        return JsonResponse(ret)

class OrderView(APIView):
    # 需要认证,使用自定义的Authenticate类来认证,已经在全局中做了认证
    # authentication_classes = [FirstAuthenticate, Authenticate, ]
    permission_classes = [permission.MyPermission2, ]

    def get(self, request, *args, **kwargs):
        # request.user
        # request.auth
        print(request.user)  # User object (1)
        print(request.auth)  # print(request.auth)#User object (1)
        """
        权限:
        if request.user.user_type != 3:
            return HttpResponse('无权访问')
        """
        self.dispatch
        order_dict = {
   
   
   
            1: {
   
   
   
                'name': "thanlon",
                'age': 24,
                'gender': '男',
            },
            2: {
   
   
   
                'name': "kiku",
                'age': 26,
                'gender': '女',
            },
        }
        # token = request._request.GET.get('token')
        ret = {
   
   
   'code': 1000, "msg": None, 'data': None}
        try:
            ret['data'] = order_dict
        except Exception as e:
            pass
        return JsonResponse(ret)

使用权限MyPermission1,普通用访问拒绝:
Django REST framework学习笔记
使用MyPermission2,普通用户正常访问:
Django REST framework学习笔记

4.2 权限源码流程

通过源码熟悉权限的流程:
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
可以在自定的权限类中自定义权限拒绝的message:

class MyPermission1:
    message = '必须是超级用户才可以访问'
    def has_permission(self, request, view):
        # 超级用户可以访问
        if request.user.user_type != 3:
            return False
        return True

class MyPermission2:
    def has_permission(self, request, view):
        # 普通用户可以访问,超级用户不可以访问
        if request.user.user_type == 3:
            return False
        return True

Django REST framework学习笔记

4.3 全局权限配置

根据权限的流程,可以对权限进行全局的配置:

settings.py:

REST_FRAMEWORK = {
   
   
   
    'DEFAULT_PERMISSION_CLASSES': ['app.permission.MyPermission1', ]  # 所有的视图对应的方法都被加上这样的权限
}

permission.py:

class MyPermission1:
    message = '必须是超级用户才可以访问'
    def has_permission(self, request, view):
        # 超级用户可以访问
        if request.user.user_type != 3:
            return False
        return True

class MyPermission2:
    def has_permission(self, request, view):
        # 普通用户可以访问,超级用户不可以访问
        if request.user.user_type == 3:
            return False
        return True

源码流程概述:

1. self.dispatch
2. def dispatch(self, request, *args, **kwargs)
3. self.initial(request, *args, **kwargs)
4. self.check_permissions(request)
5. def get_permissions(self)
6. permission.has_permission(request, self)
4.4 内置权限类

Django REST framework内置了一些权限类:
Django REST framework学习笔记
按照代码规范,我们自己写的权限类应该继承这个BasePermission权限类:

from rest_framework.permissions import BasePermission

class MyPermission1(BasePermission):
    def has_permission(self, request, view):
        return True

class MyPermission2(BasePermission):
    def has_permission(self, request, view):
         return True

这里的权限类基本上都是基于Django来做的,我们一般不使用这些类,而是自己定制。

5. 访问频率控制/节流
5.1 访问频率控制基本实现

可以根据 ip地址 来对用户访问频率进行限制,所以我们可以自定这样的访问频率控制的类:

还可以通过具有唯一标识意义的用户名或者用户ID等!

throttle.py:

import time

VISIT_RECORD = {
   
   
   }


class VisitThrottle:
    def allow_request(self, request, view):
        """
        设定10s之内只能访问10次
        :param request:
        :param view:
        :return: True or False
        返回值为True表示可以访问;返回值为False或None表示访问频率太高被限制
        """
        # 获取用户的ip地址,当前request(封装)中有的就取当前的request,如果没有就到_request中取
        remote_addr = request._request.META.get('REMOTE_ADDR')
        print(remote_addr)  # 127.0.0.1
        ctime = time.time()
        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr] = [ctime]
            return True
        history = VISIT_RECORD.get(remote_addr)
        while history and history[-1] < ctime - 10:
            history.pop(-1)
        if len(history) < 10:
            history.insert(0, ctime)
            return True
        return False  # 写不写都可以,如果执行到这里说明不可访问的,返回False或None都可以表示不可以访问

    def wait(self, *args, **kwargs):
        pass

views.py:

from rest_framework.views import APIView
from .models import User, UserToken
from django.http import JsonResponse
from utils.md5 import md5
from app.throttle import VisitThrottle


class AuthView(APIView):
    authentication_classes = []
    permission_classes = []
    throttle_classes = [VisitThrottle, ]

    def post(self, request, *args, **kwargs):
        ret = {
   
   
   'code': 1000, 'msg': None}
        try:
            # 需要以form-data的方式提交
            name = request._request.POST.get('name')
            pwd = request._request.POST.get('pwd')
            instance = User.objects.filter(name=name, pwd=pwd).first()  # User object (1),
            print(type(instance))  # <class 'app.models.User'>,加不加all()结果一样
            print(instance)  # User object (1),加不加all()结果一样
            if not instance:
                ret['code'] = 1001
                ret['msg'] = '用户名或密码错误'
            else:
                token = md5(name=name)
                UserToken.objects.update_or_create(user=instance, defaults={
   
   
   'token': token})
                ret['token'] = token
        except Exception as e:
            ret['code'] = 1001
            ret['msg'] = '请求异常'
        return JsonResponse(ret)

10s内只能发送10次请求,超出10次请求,则会返回。请求被限制:
Django REST framework学习笔记
当请求被拒绝后,系统还可以返回 **距离下次可以请求的时间**,可以通过wait方法来设置:

throttle.py:

import time
# 可以放到缓存中,默认Django REST framework中就是放在缓存中
VISIT_RECORD = {
   
   
   }


class VisitThrottle:
    def __init__(self):
        self.history = None
        self.ctime = None

    def allow_request(self, request, view):
        """
        设定10s之内只能访问10次
        :param request:
        :param view:
        :return: True or False
        返回值为True表示可以访问;返回值为False或None表示访问频率太高被限制
        """
        # 获取用户的ip地址,当前request(封装)中有的就取当前的request,如果没有就到_request中取
        remote_addr = request._request.META.get('REMOTE_ADDR')
        print(remote_addr)  # 127.0.0.1
        self.ctime = time.time()  # 1593151531.1494734
        print(self.ctime)
        if remote_addr not in VISIT_RECORD:
            VISIT_RECORD[remote_addr] = [self.ctime]
            return True
        self.history = VISIT_RECORD.get(remote_addr)
        while self.history and self.history[-1] < self.ctime - 10:
            self.history.pop(-1)
        if len(self.history) < 10:
            self.history.insert(0, self.ctime)
            return True
        return False  # 写不写都可以,如果执行到这里说明不可访问的,返回False或None都可以表示不可以访问

    def wait(self, *args, **kwargs):
        """
        设置距离下次可以请求的时间
        :param args:
        :param kwargs:
        :return:默认返回None,表示使用默认
        """
        """
        当请求被拒绝,会执行wait方法
        """
        ctime = time.time()
        print(ctime)
        print(self.history[-1])
        """
        return False
        {
          "detail": "Request was throttled. Expected available in 0 seconds."
        }
        """
        return 60 - (ctime - self.history[-1])

Django REST framework学习笔记

5.2 访问频率控制源码流程

请求过来先走dispatch方法:
Django REST framework学习笔记
执行当前self.initialize_request方法:
Django REST framework学习笔记
执行self.check_throttles方法:
Django REST framework学习笔记
执行self.get_throttles方法,遍历访问控制类对象列表:
Django REST framework学习笔记
通过列表生成式生成访问控制类对象列表:
Django REST framework学习笔记
默认的访问控制类是从配置文件中获取的,也是全局的访问控制类:
Django REST framework学习笔记
Django REST framework学习笔记
如果访问被拒绝,即执行allow_request方法返回False或者None,则执行throttle.wait()方法:
Django REST framework学习笔记
Django REST framework学习笔记

5.3 访问频率全局配置

同认证和权限一样在配置文件中进行配置:

settings.py:

REST_FRAMEWORK = {
   
   
   
    'DEFAULT_THROTTLE_CLASSES': ['app.throttle.VisitThrottle',]
}

同样某些请求可以不使用访问频率控制:

class AuthView(APIView):
    authentication_classes = []
    permission_classes = []
    # 访问频率控制
    throttle_classes = []

    def post(self, request, *args, **kwargs):
        pass
5.4 内置访问频率控制类

Django REST framewor中内置了五个访问频率控制类,所有的访问权限控制类应该继承BaseThrottle并重写其中的allow_request(self, request, view)方法:
Django REST framework学习笔记
Django REST framework学习笔记
内置的访问控制类SimpleRateThrottle其实帮助我们实现了基于IP的访问权限控制,我们看它内部是怎么实现的:
Django REST framework学习笔记
Django REST framework学习笔记
所以之前自定义的类实现的功能完全可以继承SimpleRateThrottle来实现,首先自定义类继承SimpleRateThrottle,并设置scope:

from rest_framework.throttling import SimpleRateThrottle

class VisitThrottle(SimpleRateThrottle):
    # scope被当作key使用的,根据它到配置文件中取值
    scope = 'erics'

在配置文件中添加DEFAULT_THROTTLE_RATES:

REST_FRAMEWORK = {
   
   
   
    'DEFAULT_THROTTLE_RATES': {
   
   
   
        # 每分钟访问3次
        'erics': '3/m'
    }
}

SimpleRateThrottle类中的逻辑是首先根据scope从配置文件中获取访问频率配置 **3/m**:
Django REST framework学习笔记
然后执行将获取到的rate也就是scope传入parse_rate函数进行解析:
Django REST framework学习笔记
Django REST framework学习笔记
__init__构造函数执行完成之后,执行allow_request方法:
Django REST framework学习笔记
获取key,把ip当作key:

class VisitThrottle(SimpleRateThrottle):
    # scope被当作key使用的,根据它到配置文件中取值
    scope = 'erics'

    def get_cache_key(self, request, view):
        """获取key"""
        return self.get_ident()

接下来到缓存获取所有记录:
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
之前自定义的时间,wait方法也已经做好,我们不需要去写:
Django REST framework学习笔记
最终我们只需要几行代码就可以完成对匿名用户的访问频率的控制:

from rest_framework.throttling import SimpleRateThrottle

class VisitThrottle(SimpleRateThrottle):
    # scope被当作key使用的,根据它到配置文件中取值
    scope = 'erics'

    def get_cache_key(self, request, view):
        """获取key"""
        return self.get_ident(request)


REST_FRAMEWORK = {
   
   
   
    'DEFAULT_THROTTLE_CLASSES': ['app.throttle.VisitThrottle', ],
    'DEFAULT_THROTTLE_RATES': {
   
   
   
        # 每分钟访问5次,/右边只要首字母是m就可以了
        'erics': '5/m'
    }
}

匿名用户每分钟只能访问5次:
Django REST framework学习笔记
上面是对匿名用户的访问登录控制,也可以对登录用户做访问频率控制。只需要根据用户名来做频率控制条件:

from rest_framework.throttling import SimpleRateThrottle

class UserVisitThrottle(SimpleRateThrottle):
    # scope被当作key使用的,根据它到配置文件中取值
    scope = 'user_erics'

    def get_cache_key(self, request, view):
        """获取key"""
        print(request)  # <rest_framework.request.Request object at 0x7f155c6b86d0>
        # 用户认证成功之后就会有request.user
        print(request.user)  # User object (1)
        print(request.user.name)  # thanlon
        return request.user.name


REST_FRAMEWORK = {
   
   
   
    # 'DEFAULT_THROTTLE_CLASSES': ['app.throttle.VisitThrottle', ],
    # 登录的用户使用根据用户名来做频率限制,匿名用户使用IP来做频率限制。这里全局配置了登录用户的,匿名用户需要可以单独设置通过ip来控制
    'DEFAULT_THROTTLE_CLASSES': ['app.throttle.UserVisitThrottle', ],
    'DEFAULT_THROTTLE_RATES': {
   
   
   
        # 每分钟访问5次,/右边只要首字母是m就可以了
        'erics': '5/m',
        'user_erics': '10/m'
    }
}

登录的用户每分钟只能访问10次:
Django REST framework学习笔记

6. DRF版本
6.1 GET传参获取版本

RESTful规范中规定版本可以放到URL上,如 http://127.0.0.1:8000/api/users/?version=v2 通过GET进行传参。自定义版本实现:

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.request import Request
from rest_framework.versioning import BaseVersioning

class ParamVersion:
    def determine_version(self, request, *args, **kwargs):
        # version = request._request.GET.get('version')
        version = request.query_params.get('version')
        return version

class UsersView(APIView):
    versioning_class = ParamVersion  # request.version就会有值

    def get(self, request, *args, **kwargs):
        # request是Request的对象,如果封装的request没有回通过getattr方法到原生的Django的request中找
        # version = request._request.GET.get('version')
        # version = request.query_params.get('version')
        version = request.version
        # print(request.version)
        return HttpResponse('%s' % version)

如果使用内置的版本类,实际上我们 **不需要再自定义获取版本的类**,直接在视图类方法中通过 request.version 获取就可以,因为内置已经帮我们实现了。借助内置类,我们可以少写很多代码:

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.versioning import QueryParameterVersioning

class UsersView(APIView):
    versioning_class = QueryParameterVersioning

    def get(self, request, *args, **kwargs):
        version = request.version
        return HttpResponse('%s' % version)

可以在配置文件中做默认的配置:

REST_FRAMEWORK = {
   
   
   
    'DEFAULT_VERSION': 'v1',  # 不传参或者version写错了则获取到的版本号是v1
    'ALLOWED_VERSIONS': ['v1', 'v2'],  # 版本号必须是v1或者v2,否则报错如:http://xxx/api/users/?version=v3
    'VERSION_PARAM': 'version',
}

Django REST framework学习笔记

6.2 URL路径获取版本

通过GET进行传参用的相对少一些,比较多的是在URL路径上传参,即 **``**。只需要修改URL,然后在视图中引入 URLPathVersioning 内置版本类:

api/urls.py:

from django.urls import path, re_path
from . import views

urlpatterns = [
    # path('/users/', views.UsersView.as_view()),
    re_path('(?P<version>[v1,v2]+)/users/', views.UsersView.as_view()),
]

版本是一次性配置,可以把版本的类加入到配置文件中:

settings.py:

REST_FRAMEWORK = {
   
   
   
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',  # 使用URL路径,下面的参数可以不配置,只要URL正则匹配就可以
    'DEFAULT_VERSION': 'v1',  # 不传参或者version写错了则获取到的版本号是v1
    'ALLOWED_VERSIONS': ['v1', 'v2'],  # 版本号必须是v1或者v2,否则报错如:http://xxx/api/users/?version=v3
    'VERSION_PARAM': 'version',
}

GET传参适用的内置类QueryParameterVersioning也可以放到配置文件中,这样降低了类和类之间的耦合度。

views.py:

from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView

class UsersView(APIView):

    def get(self, request, *args, **kwargs):
        version = request.version
        return HttpResponse('%s' % version)

Django REST framework学习笔记

6.3 内置版本类源码流程

Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记

通过reserve反向生成url:

from django.urls import path, re_path
from . import views

urlpatterns = [
    # path('users/', views.UsersView.as_view()),
    re_path('(?P<version>[v1,v2]+)/users/', views.UsersView.as_view(), name='user'),
]


from django.shortcuts import HttpResponse
from rest_framework.views import APIView


class UsersView(APIView):

    def get(self, request, *args, **kwargs):
        # 获取版本
        version = request.version
        # 获取处理版本的对象
        versioning_scheme = request.versioning_scheme
        # 所有的版本类对象中有reverse方法用来反向生成url的,版本自动生成。不需要加上version参数,request=request表示在request自动设置上当前的版本
        url = request.versioning_scheme.reverse(viewname='user', request=request)
        self.dispatch
        return HttpResponse('%s' % (url,))

Django REST framework学习笔记
也可以适用Django的反向生成url,只不过要手动加上版本参数:
Django REST framework学习笔记
Django REST framework学习笔记

6.4 内置版本类

Django REST framework内置了5个版本类,自定义版本类需要继承BaseVersioning,但是一般我们不需要自定义,内置的已经够我们使用的。QueryParameterVersioning是通过在URL中使用GET传参;URLPathVersioning是URL路径;HostNameVersioning是基于子域名做的;NamespaceVersioning是基于namespace,但是不常用;AcceptHeaderVersioning是基于请求头。
Django REST framework学习笔记
放到cookie中也是可以的,只要后端能正常接收。

7. DRF解析器
7.1 Django中数据的解析

Django接收请求和请求相关的数据时对请求头和数据格式有一定的要求,首先看下对请求头要求。只有请求头中有 **application/x-www-form-urlencoded**,request.POST中才可能有值(去request.body中解析数据):

urls.py:

from django.urls import path, re_path
from . import views

urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/django_request/', views.DjangoRequest.as_view()),
]

views.py:

from django.shortcuts import HttpResponse
from rest_framework.views import APIView

class DjangoRequest(APIView):
    def post(self, request, *args, **kwargs):
        from django.core.handlers.wsgi import WSGIRequest
        print(type(request._request))  # <class 'django.core.handlers.wsgi.WSGIRequest'>
        return HttpResponse()

可以看下源码中是如何做的:
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
上面说过即便带着这个Content-Type也不一定有值,数据解析(转换)时对数据格式也是有要求的,数据格式需要是 ?name=thanlon&age=23 这种格式。

之后遇到request.POST没有值,可以考虑这两个因素。

Form表单提交默认的Content-Type就是application/x-www-form-urlencoded,数据格式也是?name=thanlon&age=23。如果是Ajax提交:

$.ajax({
   
   
   
    url:...,
    type:POST,
    data:{
   
   
   'name':'thanlon','age':23}, // 内部也会转换成?name=thanlon&age=23,再带上Content-Type:application/x-www-form-urlencoded提交过去
})

Ajax可以定制请求头,这种情况下request.body中有值,但是request.post中没有值:

$.ajax({
   
   
   
    url:...,
    headers:{
   
   
   'Content-Type':'application/json'},
    type:POST,
    data:{
   
   
   'name':'thanlon','age':23},
})

Ajax将数据转换为JSON字符串传到后台,这种情况下request.body中有值,但是request.post中还是没有值:

$.ajax({
   
   
   
    url:...,
    headers:{
   
   
   'Content-Type':'application/json'},
    type:post,
    data:JSON.stringfy({
   
   
   'name':'thanlon','age':23}), // {'name':'thanlon','age':23}
})

这种情况下request.body中是有值,可以使用 json.loads(request.body) 拿到json数据。当然,需要先把字节类型转换为字符串类型。

7.2 内置解析类的使用

常用的内置解析类有 **JSONParser和FormParser**,JSONParser类可以解析请求头中Content-Type是application/json的头的数据,FormParser类可以解析请求中Content-Type是application/x-www-form-urlencoded的头的数据。Content-Type是application/json时:

urls.py:

from django.urls import re_path
from . import views

urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/parser/', views.ParserView.as_view()),
]

views.py:

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework.parsers import JSONParser

class ParserView(APIView):
    parser_classes = [JSONParser, ]

    def post(self, request, *args, **kwargs):
        """
        允许用户发送JSON格式数据,请求头中Content-Type是application/json,数据是{'name': 'erics'}
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        # request.data会触发解析类进行数据的解析
        data = request.data
        print(type(data), data)  # <class 'dict'> {'name': 'erics'}
        return HttpResponse(f'{data}')

Django REST framework学习笔记
Content-Type是application/x-www-form-urlencoded时:

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from rest_framework.parsers import JSONParser, FormParser

class ParserView(APIView):
    parser_classes = [JSONParser, FormParser,]

    def post(self, request, *args, **kwargs):
        data = request.data
        """
        1、获取用户请求
        2、获取用户请求体
        3、获取用户请求头,需要与parser_classes = [JSONParser, FormParser]中支持的请求头进行比较
        4、JSONParser、FormParser对象解析请求体
        5、解析的结果放到request.data中
        """
        print(type(data), data)  # <class 'django.http.request.QueryDict'> <QueryDict: {'name': ['erics']}>
        return HttpResponse(f'{data}')

Django REST framework学习笔记
Content-Type是multipart/form-data时,需要用到MultiPartParser解析类:
Django REST framework学习笔记
如果都不可以解析请求的数据:
Django REST framework学习笔记

配置多个请求类时,请求头中的Content-Type与哪一个解析类匹配就使用哪个解析。

全局配置只需要在配置文件中添加解析类的路径即可:

REST_FRAMEWORK = {
   
   
   
    'DEFAULT_PARSER_CLASSES':
        [
            'rest_framework.parsers.JSONParser',
            'rest_framework.parsers.FormParser',
            'rest_framework.parsers.MultiPartParser',
        ]
}
7.3 内置解析类

Django REST framework内置的解析类实际上有4种,都是根据请求头中Content-Type值的不同来对数据做不同的解析:
Django REST framework学习笔记

7.4 解析源码流程

Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记

8. DRF序列化
8.1 序列化基本使用

数据准备:

models.py:

from django.db import models


class UserInfo(models.Model):
    user_type_choices = (
        (1, '普通用户'),
        (2, 'VIP用户'),
        (3, 'SVIP用户'),
    )
    user_type = models.IntegerField(choices=user_type_choices)
    name = models.CharField(max_length=32, unique=True)
    pwd = models.CharField(max_length=64)
    user_group = models.ForeignKey('UserGroup', on_delete=models.CASCADE)
    role = models.ManyToManyField('Role')


class Token(models.Model):
    user_info = models.OneToOneField(to='UserInfo', on_delete=models.CASCADE)
    token = models.CharField(max_length=64)


class UserGroup(models.Model):
    title = models.CharField(max_length=32)


class Role(models.Model):
    title = models.CharField(max_length=32)

生成的数据表:
Django REST framework学习笔记
在角色表中添加如下数据:
Django REST framework学习笔记
原先使用 json.dumps 方法对从数据库中获取到的数据进行序列化:

urls.py:

from django.urls import path, re_path
from . import views

urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/roles/', views.RolesView.as_view()),
]

views.py:

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json

class RolesView(APIView):
    def get(self, request, *args, **kwargs):
        roles = models.Role.objects.all()
        print(roles)  # <QuerySet [<Role: Role object (1)>, <Role: Role object (2)>]>
        roles = models.Role.objects.all().values('id', 'title')
        print(roles)  # <QuerySet [{'id': 1, 'title': '管理员'}, {'id': 2, 'title': '超级管理员'}]>
        roles = list(roles)  # [<Role: Role object (1)>, <Role: Role object (2)>]
        print(roles)  # [{'id': 1, 'title': '管理员'}, {'id': 2, 'title': '超级管理员'}]
        ret = json.dumps(roles, ensure_ascii=False)
        return HttpResponse(ret)

Django REST framework学习笔记
现在我们可以使用Django REST framework中的序列化来对从数据库中的获取的数据进行序列化:

views.py:

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers

class MySerializers(serializers.Serializer):
    """
    自定义序列化类
    """
    id = serializers.IntegerField()
    title = serializers.CharField()

class RolesView(APIView):
    def get(self, request, *args, **kwargs):
        roles = models.Role.objects.all()
        # 因为对象不止一个,序列化[obj,obj,obj]这种,要使用many=True
        serializers = MySerializers(instance=roles, many=True)
        print(serializers)
        """
        MySerializers(instance=<QuerySet [<Role: Role object (1)>, <Role: Role object (2)>]>, many=True):
        id = IntegerField()
        title = CharField()
        """
        # serializers.data是已经转换完成的结果
        print(serializers.data) # [OrderedDict([('id', 1), ('title', '管理员')]), OrderedDict([('id', 2), ('title', '超级管理员')])]
        
        ret = json.dumps(serializers.data, ensure_ascii=False)
        return HttpResponse(ret)

Django REST framework学习笔记
对于从数据库中获取一条数据,如果适用序列化:

views.py:

from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers


class MySerializers(serializers.Serializer):
    """
    自定义序列化类
    """
    id = serializers.IntegerField()
    title = serializers.CharField()


class RolesView(APIView):
    def get(self, request, *args, **kwargs):
        roles = models.Role.objects.first()
        # 因为就一个对象,序列化obj,要使用many=False
        serializers = MySerializers(instance=roles, many=False)  # 默认也是False
        print(serializers)
        """
        MySerializers(instance=<Role: Role object (1)>):
        id = IntegerField()
        title = CharField()
        """
        print(serializers.data)  # {'id': 1, 'title': '管理员'}
        # serializers.data是已经转换完成的结果
        ret = json.dumps(serializers.data, ensure_ascii=False)
        return HttpResponse(ret)

Django REST framework学习笔记

8.2 自定义字段

Django REST framework的序列化可以允许我们自定义字段,从数据库中获取字段值也特别方便:

from django.urls import path, re_path
from . import views

urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/userinfo/', views.UserinfoView.as_view()),
]


from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers

class UserinfoSerializer(serializers.Serializer):
    username = serializers.CharField()
    pwd = serializers.CharField()
    user_type_id = serializers.CharField(source='user_type')  # source对应数据库中字段,row.user_type
    user_type_title = serializers.CharField(source='get_user_type_display')  # row.get_user_type_display()
    group_title = serializers.CharField(source='user_group.title')
    rls = serializers.SerializerMethodField()  # 自定义展示

    def get_rls(self, row):
        row_obj_list = row.role.all()
        ret = []
        for item in row_obj_list:
            ret.append({
   
   
   'id': item.id, 'title': item.title})
        return ret


class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True)
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

Django REST framework学习笔记

8.3 ModelSerializer

ModelSerializer类继承了Serializer,内部做了一些操作可以自动生成所有的字段:

class UserinfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = "__all__"

class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True)
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

Django REST framework学习笔记
简单的可以直接用数据库的字段适用ModelSerializer生成,复杂的可以自定义:

class UserinfoSerializer(serializers.ModelSerializer):
    user_type_title = serializers.CharField(source='get_user_type_display')
    group_title = serializers.CharField(source='user_group.title')
    rls = serializers.SerializerMethodField()

    class Meta:
        model = models.UserInfo
        # fields = "__all__"
        fields = ['id', 'username', 'pwd', 'rls', 'user_type_title', 'group_title',]

    def get_rls(self, row):
        row_obj_list = row.role.all()
        ret = []
        for item in row_obj_list:
            ret.append({
   
   
   'id': item.id, 'title': item.title})
        return ret


class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True)
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

Django REST framework学习笔记
生成字段的时候可以额外加一些参数,可以不用再定义group_title:

class UserinfoSerializer(serializers.ModelSerializer):
    user_type_title = serializers.CharField(source='get_user_type_display')
    # group_title = serializers.CharField(source='user_group.title')
    rls = serializers.SerializerMethodField()

    class Meta:
        model = models.UserInfo
        # fields = "__all__"
        fields = ['id', 'username', 'pwd', 'rls', 'user_type_title', ]
        extra_kwargs = {
   
   
   'group_title': {
   
   
   'source': 'user_group.title'}}  # 和上面自定义一样

    def get_rls(self, row):
        row_obj_list = row.role.all()
        ret = []
        for item in row_obj_list:
            ret.append({
   
   
   'id': item.id, 'title': item.title})
        return ret

class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True)
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

Django REST framework学习笔记

8.4 深度控制

只需要在Meta中设置 depth 字段就可以 自动序列化连表 获取关联表中的字段:

class UserinfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = "__all__"
        """
        depth:0~10,0表示只获取UserInfo中的表中的字段的值
        """
        depth = 1

class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True)
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

Django REST framework学习笔记

class UserinfoSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserInfo
        fields = ['id', 'username', 'pwd', 'user_type', 'user_group', 'role']
        depth = 1

Django REST framework学习笔记

8.5 生成链接

Django REST framework中的序列化也可以帮助我们生成超链接:

urls.py:

from django.urls import path, re_path
from . import views

urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/userinfo/', views.UserinfoView.as_view()),
    re_path('(?P<version>[v1,v2]+)/group/(?P<pk>\d+)', views.GroupView.as_view(), name='gp'),
]


from django.shortcuts import HttpResponse
from rest_framework.views import APIView
from . import models
import json
from rest_framework import serializers

class UserinfoSerializer(serializers.ModelSerializer):
    group = serializers.HyperlinkedIdentityField(view_name='gp', lookup_url_kwarg='pk',
                                                 lookup_field='user_group_id')  # pk和url上自定义的pk有关系

    class Meta:
        model = models.UserInfo
        fields = ['id', 'username', 'pwd', 'user_type', 'user_group', 'role', 'group']
        depth = 1

class UserinfoView(APIView):
    def get(self, request, *args, **kwargs):
        userinfo = models.UserInfo.objects.all()
        userinfo_serializer = UserinfoSerializer(userinfo, many=True, context={
   
   
   'request': request})
        ret = json.dumps(userinfo_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")


class GroupSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.UserGroup
        fields = '__all__'


class GroupView(APIView):
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')  # url传过来的pk对应/(?P<version>[v1,v2]+)/group/(?P<pk>\d+)/
        obj = models.UserGroup.objects.filter(pk=pk).first()
        group_serializer = GroupSerializer(instance=obj, many=False)
        ret = json.dumps(group_serializer.data, ensure_ascii=False)
        return HttpResponse(f"{ret}")

Django REST framework学习笔记
Django REST framework学习笔记

8.6 请求数据校验

Django REST framework序列化还可以做 **请求数据校验**,简单的数据校验:

class UserGroupSerializer(serializers.Serializer):
    # title = serializers.CharField(error_messages={'required':'dsdsd'}) # error_messages暂时没作用
    # 写需要校验的字段
    title = serializers.CharField()
    
    def validate_title(self, value):
        from rest_framework import exceptions
        raise exceptions.ValidationError('错误!')
        return value

class UserGroupView(APIView):
    def post(self, request, *args, **kwargs):
        print(request.data)  # {'title': ''} 
        ser = UserGroupSerializer(data=request.data)
        if not ser.is_valid():
            print(
                ser.errors['title'][0])  # {'title': [ErrorDetail(string='This field may not be blank.', code='blank')]}
        else:
            print(ser.validated_data,
                  type(ser.validated_data))  # OrderedDict([('title', '3组')]) <class 'collections.OrderedDict'>
            print(ser.validated_data['title'])  # 3组
        return HttpResponse()

Django REST framework学习笔记
Django REST framework学习笔记

8.7 自定义验证规则

简单的数据校验一般不能满足需求,很多情况下需要自定义验证规则校验数据:

class UserGroupValidator:
    def __init__(self, base):
        self.base = str(base)

    def __call__(self, value):
        """数据一提交过来就会执行这个__call__方法"""
        print('提交过来title的值', value)  # value是提交过来的值
        if not value.endswith(self.base):
            message = '标题必须以%s结尾!' % self.base
            raise serializers.ValidationError(message)

    def set_context(self, serializer_field):
        """执行验证之前调用,serializer_field是当前字段对象,这里用不到"""
        pass


class UserGroupSerializer(serializers.Serializer):
    title = serializers.CharField(validators=[UserGroupValidator('组'), ])


class UserGroupView(APIView):
    def post(self, request, *args, **kwargs):
        # print(request.data)  # {'title': '3'}
        ser = UserGroupSerializer(data=request.data)
        if not ser.is_valid():
            print(
                ser.errors['title'][0])  # {'title': [ErrorDetail(string='This field may not be blank.', code='blank')]}
        else:
            print(ser.validated_data,
                  type(ser.validated_data))  # OrderedDict([('title', '3组')]) <class 'collections.OrderedDict'>
            print(ser.validated_data['title'])  # 3组
        return HttpResponse()

Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
自定义验证规则时,需要用到钩子函数,需要从 is_valid 方法开始找。

9. DRF分页
9.1 内置分页

① 查看第 n 页,每页显示 m 条数据。**settings.py** 中配置的是默认显示的数据条数。使用到的内置类:**PageNumberPagination**,

settings.py

REST_FRAMEWORK = {
   
   
   
    'PAGE_SIZE': 2,
}

views.py:

from rest_framework import serializers
from api import models
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination


class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class PagerView(APIView):
    def get(self, request, *args, **kwargs):
        # 获取所有数据
        roles = models.Role.objects.all()
        # 创建分页对象
        pg = PageNumberPagination()
        # 获取数据库中分页的数据
        pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)
        """
        print(pager_roles) # [<Role: Role object (1)>, <Role: Role object (2)>]
        """
        # 序列化数据
        serializer = PagerSerializer(instance=pager_roles, many=True)
        """
        ret = json.dumps(serializer.data)
        return HttpResponse(ret)
        """
        return Response(serializer.data)

Django REST framework学习笔记
Django REST framework学习笔记
② 第 n 页向前向后查 m 条数据,使用到的内置类:**LimitOffsetPagination**

settings.py

REST_FRAMEWORK = {
   
   
   
    'PAGE_SIZE': 2,
}


from rest_framework import serializers
from api import models
from rest_framework.response import Response
from rest_framework.pagination import LimitOffsetPagination


class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class PagerView(APIView):
    def get(self, request, *args, **kwargs):
        # 获取所有数据
        roles = models.Role.objects.all()
        # 创建分页对象
        pg = LimitOffsetPagination()
        # 获取数据库中分页的数据
        pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)
        """
        print(pager_roles) # [<Role: Role object (1)>, <Role: Role object (2)>]
        """
        # 序列化数据
        serializer = PagerSerializer(instance=pager_roles, many=True)
        """
        ret = json.dumps(serializer.data)
        return HttpResponse(ret)
        """
        return Response(serializer.data)

Django REST framework学习笔记
Django REST framework学习笔记
③ 解决数据量比较大时,降低扫描的数据量。同时要对页码进行加密,防止因用户随意指定页码没有实现降低扫描数据量而提高查询效率的目的。使用到的内置类:**CursorPagination这部分需不能直接使用内置累,需要自定义类来实现!** 下面会有介绍。

9.2 自定义分页

① 查看第 n 页,每页显示 m 条数据

settings.py

REST_FRAMEWORK = {
   
   
   
    'PAGE_SIZE': 2,
}

views.py:

from rest_framework import serializers
from api import models
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination


class MyPageNumberPagination(PageNumberPagination):
    page_size = 2  # 在这里设置可以覆盖settings.py中的配置
    page_query_param = 'page'
    page_size_query_param = 'size'
    max_page_size = 3


class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class PagerView(APIView):
    def get(self, request, *args, **kwargs):
        # 获取所有数据
        roles = models.Role.objects.all()
        # 创建分页对象
        pg = MyPageNumberPagination()
        # 获取数据库中分页的数据
        pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)
        """
        print(pager_roles) # [<Role: Role object (1)>, <Role: Role object (2)>]
        """
        # 序列化数据
        serializer = PagerSerializer(instance=pager_roles, many=True)
        """
        ret = json.dumps(serializer.data)
        return HttpResponse(ret)
        return Response(serializer.data)
        """
        return Response(serializer.data)

Django REST framework学习笔记

② 第 n 页向前向后查 m 条数据

settings.py

REST_FRAMEWORK = {
   
   
   
    'PAGE_SIZE': 2,
}

views.py:

from rest_framework import serializers
from api import models
from rest_framework.response import Response
from rest_framework.pagination import LimitOffsetPagination

class MyLimitOffsetPagination(LimitOffsetPagination):
    limit_query_param = 'limit'
    offset_query_param = 'offset'
    max_limit = 2


class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class PagerView(APIView):
    def get(self, request, *args, **kwargs):
        # 获取所有数据
        roles = models.Role.objects.all()
        # 创建分页对象
        pg = MyLimitOffsetPagination()
        # 获取数据库中分页的数据
        pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)
        """
        print(pager_roles) # [<Role: Role object (1)>, <Role: Role object (2)>]
        """
        # 序列化数据
        serializer = PagerSerializer(instance=pager_roles, many=True)
        """
        ret = json.dumps(serializer.data)
        return HttpResponse(ret)
        return Response(serializer.data)
        """
        return Response(serializer.data)

Django REST framework学习笔记
③ 降低扫描的数据量,同时对页码进行加密

settings.py

REST_FRAMEWORK = {
   
   
   
    'PAGE_SIZE': 2,
}

views.py:

from rest_framework import serializers
from api import models
from rest_framework.response import Response
from rest_framework.pagination import CursorPagination


class MyCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'
    page_size = 2
    ordering = 'id'  # 倒序是-id
    page_size_query_param = None
    max_page_size = None


class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class PagerView(APIView):
    def get(self, request, *args, **kwargs):
        # 获取所有数据
        roles = models.Role.objects.all()
        # 创建分页对象
        pg = MyCursorPagination()
        # 获取数据库中分页的数据
        pager_roles = pg.paginate_queryset(queryset=roles, request=request, view=self)
        """
        print(pager_roles) # [<Role: Role object (1)>, <Role: Role object (2)>]
        """
        # 序列化数据
        serializer = PagerSerializer(instance=pager_roles, many=True)
        """
        ret = json.dumps(serializer.data)
        return HttpResponse(ret)
        return Response(serializer.data)
        return Response(serializer.data)
        """
        return pg.get_paginated_response(serializer.data)

Django REST framework学习笔记
Django REST framework学习笔记

get_paginated_response方法可以返回更多的内容!

10. DRF视图
10.1 GenericAPIView

视图继承 GenericAPIView ,**GenericAPIView** 继承 **APIView**, APIView 继承
Django REST framework学习笔记
Django REST framework学习笔记
settings.py:

REST_FRAMEWORK = {
   
   
   
    'PAGE_SIZE': 2,
}

urls.py:

from django.urls import path, re_path
from . import views

urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/testview/', views.TestView.as_view()),
]

views.py:

from rest_framework import serializers
from rest_framework.generics import GenericAPIView
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response


class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class TestView(GenericAPIView):
    queryset = models.Role.objects.all()
    pagination_class = PageNumberPagination
    serializer_class = PagerSerializer

    def get(self, request, *args, **kwargs):
        # 获取数据
        roles = self.get_queryset()  # queryset: models.Role.objects.all()
        # 分页
        pager_roles = self.paginate_queryset(roles)
        # 序列化
        serializer = self.get_serializer(instance=pager_roles, many=True)
        return Response(serializer.data)

Django REST framework学习笔记

一般用不到GenericAPIView!

10.2 GenericViewSet

视图继承 **GenericViewSet**,可以根据请求方法的不同把请求分发到不同的方法,比原来都分发到 get 然后判断有无 id 要好一些。 GenericViewSet 继承 ViewSetMixin 和 **GenericAPIView**。
Django REST framework学习笔记
Django REST framework学习笔记

ViewSetMixin只是重写了as_view方法!

settings.py:

REST_FRAMEWORK = {
   
   
   
    'PAGE_SIZE': 2,
}

urls.py:

from django.urls import path, re_path
from . import views

urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/testview/', views.TestView.as_view({
   
   
   'get': 'list'})),
]

views.py:

from rest_framework import serializers
from rest_framework.viewsets import GenericViewSet
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response


class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class TestView(GenericViewSet):
    queryset = models.Role.objects.all()
    pagination_class = PageNumberPagination
    serializer_class = PagerSerializer

    def list(self, request, *args, **kwargs):
        # 获取数据
        roles = self.get_queryset()  # queryset: models.Role.objects.all()
        # 分页
        pager_roles = self.paginate_queryset(roles)
        # 序列化
        serializer = self.get_serializer(instance=pager_roles, many=True)
        return Response(serializer.data)

Django REST framework学习笔记

页码是从1开始的!

10.3 ModelViewSet

ModelViewSet 继承6个类:
Django REST framework学习笔记
settings.py:

REST_FRAMEWORK = {
   
   
   
    'PAGE_SIZE': 2,
}

urls.py:

from django.urls import path, re_path
from . import views

urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/testview/', views.TestView.as_view({
   
   
   'get': 'list','post':'create'})),
    re_path('(?P<version>[v1,v2]+)/testview/(?P<pk>\d+)', views.TestView.as_view(
        {
   
   
   'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'}
    )),
]

views.py:

from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination


class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class TestView(ModelViewSet):
    queryset = models.Role.objects.all()
    pagination_class = PageNumberPagination
    serializer_class = PagerSerializer

Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记

10.4 视图的使用

增删改查:**ModelViewSet**

增删:**CreateModelMixin** 和 CreateModelMixin 还有 GenericViewSet

复杂逻辑: GenericViewSetAPIView

11. DRF路由
11.1 基本路由

urls.py:

urlpatterns = [
    # http://127.0.0.1:8000/api/v1/testview/?format=json
    re_path('(?P<version>[v1,v2]+)/testview/', views.TestView.as_view({
   
   
   'get': 'list','post':'create'})),
    # http://127.0.0.1:8000/api/v1/testview.json
    re_path('(?P<version>[v1,v2]+)/testview\.(?P<format>\w+)', views.TestView.as_view({
   
   
   'get': 'list','post':'create'})),
    # http://127.0.0.1:8000/api/v1/testview/1?format=json
    re_path('(?P<version>[v1,v2]+)/testview/(?P<pk>\d+)', views.TestView.as_view({
   
   
   'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
    # http://127.0.0.1:8000/api/v1/testview/1.json
    re_path('(?P<version>[v1,v2]+)/testview/(?P<pk>\d+)\.(?P<format>\w+)', views.TestView.as_view({
   
   
   'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
]

Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记
Django REST framework学习笔记

11.2 自动生成路由

Django REST framework渲染器可以自动帮助我们生成路由,查看生成的路由信息:

urls.py:

from django.urls import re_path, include
from . import views
from rest_framework import routers

router = routers.DefaultRouter()
router.register('x', views.TestView)
router.register('xx', views.TestView)
urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/', include(router.urls))
]

views.py:

from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination


class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class TestView(ModelViewSet):
    queryset = models.Role.objects.all()
    pagination_class = PageNumberPagination
    serializer_class = PagerSerializer

Django REST framework学习笔记

每一个生成四个,分别是增删改查!如果增删改查都使用,则可以使用自动生成!

Django REST framework学习笔记

12. DRF渲染器
12.1 JSONRenderer

直接显示JSON字符串:

urls.py:

from django.urls import re_path, include
from . import views
from rest_framework import routers

router = routers.DefaultRouter()
router.register('x', views.TestView)
router.register('xx', views.TestView)
urlpatterns = [
    re_path('(?P<version>[v1,v2]+)/', include(router.urls))
]

settings.py:

REST_FRAMEWORK = {
   
   
   
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ]
}

views.py:

from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer

class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class TestView(ModelViewSet):
    renderer_classes = [JSONRenderer]
    queryset = models.Role.objects.all()
    pagination_class = PageNumberPagination
    serializer_class = PagerSerializer

Django REST framework学习笔记

12.2 BrowsableAPIRenderer

显示更好看的压面:

views.py:

from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer

class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class TestView(ModelViewSet):
    renderer_classes = [JSONRenderer]
    queryset = models.Role.objects.all()
    pagination_class = PageNumberPagination
    serializer_class = PagerSerializer

Django REST framework学习笔记

12.3 AdminRenderer

views.py:

from rest_framework import serializers
from rest_framework.viewsets import ModelViewSet
from rest_framework.pagination import PageNumberPagination
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer,AdminRenderer

class PagerSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Role
        fields = "__all__"


class TestView(ModelViewSet):
    renderer_classes = [JSONRenderer,BrowsableAPIRenderer,AdminRenderer]
    queryset = models.Role.objects.all()
    pagination_class = PageNumberPagination
    serializer_class = PagerSerializer

Django REST framework学习笔记

AdminRenderer一般不用!

本文同步分享在 博客“Erics-1996”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
3年前
Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法
Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法参考文章:(1)Google地球出现“无法连接到登录服务器(错误代码:c00a0194)”解决方法(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.codeprj.com%2Fblo
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这