Django 之 DRF-CBV (基于类的视图)

简介

  • FBV(function base views) 基于函数的视图,就是在视图里使用函数处理请求。
  • CBV(class base views) 基于类的视图,就是在视图里使用类处理请求。
  • views.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    from django.http import HttpResponse
    from django.views import View
    from django.shortcuts import render

    from user.models import User


    # Create your views here.
    class RegisterView(View):
    def get(self, request):
    return render(request, 'register.html')

    def post(self, request):
    username = request.POST.get('username')
    password = request.POST.get('password')
    repassword = request.POST.get('repassword')
    if password == repassword:
    if user := User.objects.create(username=username, password=password):
    return HttpResponse(f'{user}注册成功!')
    return HttpResponse('注册失败')

  • register.html

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>注册</title>
    </head>
    <body>
    <h1>注册</h1>
    <form action="{% url 'register' %}" method="post">
    {% csrf_token %}
    <p><input type="text" name="username" placeholder="username"></p>
    <p><input type="password" name="password" placeholder="password"></p>
    <p><input type="password" name="repassword" placeholder="password"></p>
    <p><input type="submit" value="注册"></p>
    </form>
    </body>
    </html>
  • urls.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    """RESTful URL Configuration

    The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.2/topics/http/urls/
    Examples:
    Function views
    1. Add an import: from my_app import views
    2. Add a URL to urlpatterns: path('', views.home, name='home')
    Class-based views
    1. Add an import: from other_app.views import Home
    2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
    Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
    """
    from django.contrib import admin
    from django.urls import path

    from user.views import RegisterView

    urlpatterns = [
    path('admin/', admin.site.urls),
    path('register', RegisterView.as_view(), name='register')
    ]

原生实现 (View)

  • views.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    from django.http import JsonResponse
    from django.views import View
    from django.shortcuts import render

    from user.models import User


    # Create your views here.
    class UserView(View):
    def get(self, request, uid):
    user = User.objects.get(pk=uid)
    return JsonResponse({'status': 200, 'user': user.to_dict()})

    def post(self, request, uid):
    username = request.POST.get('username')
    password = request.POST.get('password')
    repassword = request.POST.get('repassword')
    if password == repassword:
    if User.objects.create(username=username, password=password):
    return JsonResponse({'status': 200, 'msg': '注册成功'})
    return JsonResponse({'status': 200, 'msg': '注册失败'})

  • models.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    from django.db import models


    # Create your models here.
    class User(models.Model):
    username = models.CharField(max_length=20, unique=True, verbose_name='用户名')
    password = models.CharField(max_length=20, verbose_name='密码')

    class Meta:
    db_table = 'user'
    verbose_name = '用户表'
    verbose_name_plural = verbose_name

    def __str__(self):
    return self.username

    # 手动序列化
    def to_dict(self):
    return {'id': self.id, 'username': self.username, 'password': self.password}

  • urls.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    """RESTful URL Configuration

    The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/3.2/topics/http/urls/
    Examples:
    Function views
    1. Add an import: from my_app import views
    2. Add a URL to urlpatterns: path('', views.home, name='home')
    Class-based views
    1. Add an import: from other_app.views import Home
    2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
    Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
    """
    from django.contrib import admin
    from django.urls import path

    from user.views import RegisterView, UserView

    urlpatterns = [
    path('admin/', admin.site.urls),
    path('user/<int:uid>', UserView.as_view(), name='user')
    ]

序列化

  • 简介

    • 序列化:对象 ---> IO 中传输的格式
    • 反序列化:IO 中传输的格式 ---> 对象
  • 注意事项

    • 如果想使用序列化和 APIView,必须安装:
      1
      pip install djangorestframework
    • 然后将 rest_framework 添加到 settings.py 中的 INSTALLED_APPS 里,如下:
      1
      2
      3
      4
      5
      INSTALLED_APPS = [
      ...
      'user.apps.UserConfig',
      'rest_framework',
      ]
  • 创建模型 (models.py)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    from django.db import models


    # Create your models here.
    class User(models.Model):
    username = models.CharField(max_length=20, unique=True)
    password = models.CharField(max_length=128)
    phone = models.CharField(max_length=11)
    add_time = models.DateTimeField(auto_now=True)

    class Meta:
    db_table = 'user'

    def __str__(self):
    return self.username

  • 原生序列化

    • 应用目录下创建名为 serializers.py 文件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      from rest_framework import serializers

      from user.models import User


      class UserSerializer(serializers.Serializer):
      # 定义需要序列化的字段
      id = serializers.IntegerField(read_only=True)
      username = serializers.CharField(max_length=20, min_length=5, required=True)
      password = serializers.CharField(max_length=128, required=True)
      phone = serializers.CharField(max_length=11, min_length=11)
    • 使用序列化类:views.py

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      from django.contrib.auth.hashers import make_password
      from django.shortcuts import render
      from rest_framework.views import APIView
      from django.http import JsonResponse

      from user.serializers import UserSerializer
      from user.models import User


      # Create your views here.
      class UserViews(APIView):
      def get(self, request):
      pass

      def post(self, request):
      # 获取POST中的值
      username = request.POST.get('username')
      password = request.POST.get('password')
      phone = request.POST.get('phone')
      password = make_password(password)
      # 构建对象
      user = User.objects.create(username=username, password=password, phone=phone)
      # 将对象传递给UserSerializer
      us = UserSerializer(user)
      # 获取序列化后的数据:us.data
      # print(us.data)
      return JsonResponse({'status': 200, 'user': us.data})
  • 使用 ModelSerializers 序列化

    • serializers.py

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      class UserSerializer1(serializers.ModelSerializer):
      repassword = serializers.CharField(max_length=128, write_only=True)

      class Meta:
      model = User
      fields = ['id', 'username', 'password', 'phone', 'repassword']

      def validate(self, attrs): # attrs 就是一个提交数据的字典形式
      if attrs['password'] != attrs['repassword']:
      attrs['flag'] = False
      return attrs

      def create(self, validated_data):
      username = validated_data['username']
      password = validated_data['password']
      phone = validated_data['phone']
      # 密码加密
      password = make_password(password)

      user = User.objects.create(username=username, password=password, phone=phone)

      return user
      • 定制校验

        • 定制具体字段的校验

          1
          2
          3
          4
          5
          6
          7
          8
          class UserSerializer1(serializers.ModelSerializer):
          ......

          def validate_email(self, mail):
          if re.match(r'', email):
          return email
          else:
          raise serializers.ValidationError('邮箱错误')
        • 定制全局校验

          1
          2
          3
          4
          5
          6
          7
          class UserSerializer1(serializers.ModelSerializer):
          ......

          def validate(self, attrs): # attrs 就是一个提交数据的字典形式
          if attrs['password'] != attrs['repassword']:
          attrs['flag'] = False
          return attrs
      • 定制 create 方法:重写父类的 create 方法

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        class UserSerializer1(serializers.ModelSerializer):
        ......

        def create(self, validated_data):
        username = validated_data['username']
        password = validated_data['password']
        phone = validated_data['phone']
        # 密码加密
        password = make_password(password)

        user = User.objects.create(username=username, password=password, phone=phone)

        return user
      • ModelSerializer 之 read_only 和 write_only

        • write_only
          • 某个字段不属于指定 model,它是 write_only,需要用户传进来,但我们不能对它进行 save(),因为 ModelSerializer 是基于 Model,这个字段在 Model 中没有对应,这个时候,我们需要重写 validate() 方法!
          • 就是用户 post 过来的数据,后台服务器处理后不会再经过序列化后返回给客户端;最常见的就是我们在使用手机注册的验证码和填写的密码。
        • read_only
          • 某个字段属于指定 model,它是 read_only,表示不允许用户自己上传,只能用于 api 的输出。
          • 如果某个字段设置了 read_only=True,那么就不需要进行数据验证,只会在返回时,将这个字段序列化后返回。
          • 举个简单的例子:在用户进行购物的时候,用户 post 订单时,肯定会产生一个订单号,而这个订单号应该由后台逻辑完成,而不应该由用户 post 过来,如果不设置 read_only=True,那么验证的时候就会报错。
          • 再例如,我们在网上购物时,支付时通常会产生支付状态,交易号、订单号、支付时间等字段,这些字段都应该设置为 read_only=True,即这些字段都应该由后台产生然后返回给客户端。
    • views.py

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      from django.http import JsonResponse
      from rest_framework.views import APIView

      from user.serializers import UserSerializer1


      class UserViews1(APIView):
      def get(self, request):
      pass

      def post(self, request):
      # 只有在APIView中才能使用request.data data = JSONParser().parse(request)
      us = UserSerializer1(data=request.data)
      if us.is_valid(): # 验证
      us.save() # 保存
      return JsonResponse({'status': 200, 'user': us.data})
  • 关系模型序列化

    • models.py (一对多)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      from django.db import models


      # Create your models here.
      # 一
      class UserType(models.Model):
      name = models.CharField(max_length=20, unique=True)
      add_time = models.DateTimeField(auto_now=True)

      class Meta:
      db_table = 'user_type'


      # 多
      class User(models.Model):
      username = models.CharField(max_length=20, unique=True)
      password = models.CharField(max_length=128)
      phone = models.CharField(max_length=11)
      add_time = models.DateTimeField(auto_now=True)
      usertype = models.ForeignKey(to=UserType, on_delete=models.CASCADE, related_name='users', null=True)

      class Meta:
      db_table = 'user'

      def __str__(self):
      return self.username

    • serializers.py

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      from rest_framework import serializers

      from user.models import UserType


      class UserTypeSerializer(serializers.ModelSerializer):
      # 此类型下的多个用户,名称必须要与models中的外键related_name保持一致
      # users = serializers.StringRelatedField(many=True) # 名称展示
      users = serializers.PrimaryKeyRelatedField(many=True, read_only=True) # 主键展示

      class Meta:
      model = UserType
      # 自定义的字段需要添加到fields中:“users”
      fields = ['id', 'name', 'add_time', 'users']

    • views.py

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      from django.http import JsonResponse
      from rest_framework.views import APIView

      from user.serializers import UserTypeSerializer
      from user.models import UserType


      # Create your views here.
      class UserTypeView(APIView):
      def get(self, request):
      usertypes = UserType.objects.all()
      # 只要序列化的是多的内容则必须添加many=True
      serializer = UserTypeSerializer(usertypes, many=True)
      data = {
      'status': 200,
      'types': serializer.data
      }
      return JsonResponse(data)

反序列化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 序列化
# 1. 将模型实例转换为Python原生数据类型
us = UserSerializer(user)
# 2. 将数据转换成json
content = JSONRenderer().render(us.data)

# 反序列化
# 1. 将一个流(stream)解析为Python原生数据类型
import io
stream = io.BytesIO(content)
data = JSONParser().parse(stream)
# 2. 然后我们要将Python原生数据类型恢复成正常的对象实例
us = UserSerializer(data=data)
us.is_valid()
us.validated_data
us.save()

Generic views

  • serializers.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from rest_framework import serializers

    from user.models import User


    class SingleUserSerializer(serializers.ModelSerializer):
    class Meta:
    model = User
    fields = ['id', 'username', 'password', 'phone', 'usertype']

  • views.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView

    from user.models import User
    from user.serializers import SingleUserSerializer


    class UserResource(ListCreateAPIView):
    # 操作的模型
    queryset = User.objects.all()
    # 此模型对应的序列化类
    serializer_class = SingleUserSerializer


    class UserResource1(RetrieveUpdateDestroyAPIView):
    queryset = User.objects.all()
    serializer_class = SingleUserSerializer

  • urls.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    from django.urls import path, include

    from user.views import UserResource, UserResource1

    app_name = 'user'

    urlpatterns = [
    path('single', UserResource.as_view(), name='single'),
    path('single1/<int:pk>', UserResource1.as_view(), name='single1'),
    ]

ViewSets

  • views.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    from rest_framework.viewsets import ModelViewSet

    from user.models import User
    from user.serializers import SingleUserSerializer


    class UserResource2(ModelViewSet):
    queryset = User.objects.all()
    serializer_class = SingleUserSerializer

  • urls.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from django.urls import path, include
    from rest_framework.routers import DefaultRouter

    from user.views import UserResource2

    app_name = 'user'

    router = DefaultRouter()
    router.register(r'single', UserResource2)

    urlpatterns = [
    path('', include(router.urls))
    ]

------------- 本文结束 感谢您的阅读 -------------
正在加载今日诗词....