[Notas del estudio] 3 horas para obtener el marco DRF | Práctica del marco de separación frontal del marco Django REST

3 horas para obtener el marco DRF | Práctica del marco de separación frontal del marco Django REST

Prefacio (basado en el asistente de IA de INSCODE)

DRF (nombre completo Django REST framework) es un poderoso conjunto de herramientas para construir Web API. Es un Python Web framework basado en Django. Proporciona a los desarrolladores un conjunto de herramientas para el desarrollo rápido de RESTful API. Puede automatizar la visualización y documentación de API. Realiza pruebas automatizadas de interfaces y enrutamiento API automatizado, serialización, vistas, verificación, paginación, administración de versiones, autenticación y otras funciones. DRF simplifica el desarrollo de API y proporciona una serie de herramientas para crear API de alta calidad.

1.1: Introducción al curso

Objetivo de aprendizaje: usar DRF para desarrollar una interfaz RESTful API
Contenido de aprendizaje: serialización, conjunto de vistas, enrutamiento, autenticación, autoridad
Efecto del curso: varias vistas de DRF realizan la adición, eliminación, modificación y consulta de información del curso

2.1: Comprender la separación de front-end y back-end desde cuatro aspectos

  • formulario interactivo
    inserte la descripción de la imagen aquí

RESTful API es una especificación de interfaz acordada entre los extremos frontal y posterior de i

  • Modo de organización del código
    Los extremos delantero y trasero no están separados: sintaxis de plantilla de django
    Los extremos delantero y trasero están semiseparados
    Los extremos delantero y trasero están separados
  • Modo de desarrollo
    Los extremos delantero y trasero no están separados Proceso de desarrollo del proyecto:
    inserte la descripción de la imagen aquí
    los extremos delantero y trasero están separados Proceso de desarrollo del proyecto:
    inserte la descripción de la imagen aquí
  • Proceso de especificación de la interfaz de datos
    inserte la descripción de la imagen aquí

2.2 Comprensión profunda de qué es RESTful API

Puede aprender de las especificaciones de interfaz de otras personas.
Por ejemplo:
github-API
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
Comprensión profunda de lo que es RESTful API

2.3 Pycharm crea un entorno de desarrollo de proyectos

  • Configuración.py
# 因为RESTframework是有前端文件的,后面使用时会全部放到这个目录
STATIC_ROOT = os.pardir.join(BASE_DIR, "static")
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "staticfiles")
]
  • gestionar.py
makemigrations
migrate
createsuperuser

inserte la descripción de la imagen aquí

2.4 Introducción e instalación del marco

Sitio web oficial de Django Rest Framework: https://www.django-rest-framework.org/

Realice los siguientes pasos de acuerdo con la documentación:

  • 1. Instalar el paquete correspondiente
pip install djangorestframework
pip install markdown       # Markdown support for the browsable API.
pip install django-filter  # Filtering support
  • Modificar la configuración en settings.py
# Add 'rest_framework' to your INSTALLED_APPS setting.

INSTALLED_APPS = [
    ...
    "rest_framework", # 用于开发RESTful API
    'rest_framework.authtoken', # DRF自带的Token认证
]

Todas las configuraciones relevantes para el marco de descanso se colocan en un diccionario de configuraciones

# DRF的全局配置
REST_FRAMEWORK = {
    
    
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',  # 自带分页类
    'PAGE_SIZE': 50,  # 每页数据量
    'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S',  # 时间显示格式
    'DEFAULT_RENDER_CLASSES': [
        'rest_framework.renders.JSONRenderer',
        'rest_framework.renders.BrowsableAPIRenderer',
    ],  # 返回response对象所用的类
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser',
    ],  # 解析器,如何解析request请求中的request.data
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],  # 权限相关配置
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ],  # 认证相关配置
    "URL_FIELD_NAME": 'link',
}
  • Modificar la configuración en urls.py
urlpatterns = [
    ...
    path('api-auth/', include('rest_framework.urls')) # DRF的登录退出
]
  • Serialización de 20 módulos de DRF
    , vista, enrutamiento, autenticación, permisos, limitación de corriente, filtrado, analizador, renderizador, paginación, versión, prueba, resumen, manejo de excepciones, configuración, verificación, código de estado, negociación de contenido, almacenamiento en caché, metadatos

3.1 Desarrollar la clase modelo de información del curso

modelos.py

from django.db import models

# Create your models here.
from django.db import models
from django.conf import settings


class Course(models.Model):
    name = models.CharField(max_length=255, unique=True, help_text='课程名称', verbose_name='名称')
    introduction = models.TextField(help_text='课程介绍', verbose_name='介绍')
    teacher = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, help_text='课程讲师', verbose_name='讲师')
    price = models.DecimalField(max_digits=6, decimal_places=2, help_text='课程价格')
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    update_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        verbose_name = "课程信息"
        verbose_name_plural = verbose_name
        ordering = ('price',)

    def __str__(self):
        return self.name

Registre el campo en el backend para facilitar la adición de datos desde el backend de administración
admin.py

from django.contrib import admin
from .models import Course


# Register your models here.

@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
    list_display = ('name', 'introduction', 'teacher', 'price')
    search_fields = list_display
    list_filter = list_display

3.2 ¿Qué es la serialización?

La serialización también se denomina serializador, que se refiere a convertir el tipo de datos django del conjunto de consultas QuerySet o instancia de instancia de clase de modelo en json o xml, convertir
queryset o instancia en json/xml/yaml que puede ser fácilmente representado por el front-end,
por lo que serialización y deserialización es
analizar profundamente el serializador de Django para la interacción de datos de front-end y back-end

  • Inicie el proyecto, ingrese el fondo de administrador e inserte datos
    inserte la descripción de la imagen aquí
    inserte la descripción de la imagen aquí

  • Prueba el serializador de django en la consola de python

from course.models import Course
from django.core import serializers

serializers.serialize('json', Course.objects.all())
# '[{"model": "course.course", "pk": 1, "fields": {"name": "Django REST framework快速入门", "introduction": "快速入门Django REST framework,学会开发一套自己的Restful API服务,并且自动生成API文档", "teacher": 1, "price": "9.99", "created_at": "2023-07-28T10:11:46.882", "update_at": "2023-07-28T10:11:46.882"}}]'

# 如果只需要序列化一部分字段
serializers.serialize('json', Course.objects.all(), fields=("name"))
# '[{"model": "course.course", "pk": 1, "fields": {"name": "Django REST framework快速入门"}}]'

Pero el serializador de django todavía tiene mucho que mejorar
1. Procesamiento de validación: en el proceso de deserialización, cuando los datos pasados ​​por el front-end se colocan en request.data, deben convertirse en una instancia de clase modelo y luego guardarse. En este momento, es necesario verificar los datos enviados por el front-end.
2. Parámetros del validador
3. Serializar varios objetos al mismo tiempo
4. Agregar contexto durante la serialización
5. Sin manejo de excepciones para datos no válidos
6. El campo de clave externa del campo relacional solo devuelve la identificación, que debe ser manejada por nosotros mismos
El serializador de drf puede ayudarnos a resolver bien estos problemas.

3.3 Cómo heredar ModelSerializer para serializar clases modelo

Aprendizaje de Python———serializador (revisión) El método de serialización para
construir una clase de modelo serializes.py bajo la aplicación es muy similar al método de escritura de formulario durante el desarrollo de django . Primero revise la clase de formulario para la clase de modelo

from django import forms
from rest_framework import serializers  # 导入序列化器

from .models import Course


class CourseForm(forms.ModelForm):
    class Meta:
        model = Course
        fields = ('name', 'introduction', 'teacher', 'price')

La serialización de la clase modelo es casi la misma, excepto que hereda de los serializadores. ModelSerializer
teacher es una clave externa, por lo que si desea obtener el nombre correspondiente al disertante, debe serializar el nombre del usuario.
La tabla de usuarios asociada con el profesor no es un usuario nuevo cuando se crea un nuevo curso, por lo que este campo se puede configurar como de solo lectura ReadOnlyField

class CourseSerializer(serializers.ModelSerializer):
    teacher = serializers.ReadOnlyField(source='teacher.username') # 外键字段、只读
    
    class Meta:
        model = Course  # 写法和上面的CourseForm类似
        # exclude = ('id', ) # 注意元组中只有1个元素时不能写成("id")
        # fields = ('name', 'introduction', 'teacher', 'price')
        fields = "__all__"

El mismo método serializa la clase de modelo de usuario.
ModelSerializer es un nivel más alto de encapsulación. Hereda de Serializer. Para lograr una personalización más flexible, puede heredar de Serializer.
Aquí solo serializamos clases de modelo, que es relativamente simple, por lo que puede ser utilizado directamente

from django.contrib.auth.models import User

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = "__all__"

Para la serialización de campos de clave externa, puede especificar la profundidad de recorrido.
Si la estructura de la tabla tiene tablas secundarias asociadas con la tabla principal y la tabla principal está asociada con otra tabla principal, puede establecer la profundidad

class CourseSerializer(serializers.ModelSerializer):
    teacher = serializers.ReadOnlyField(source='teacher.username')  # 外键字段、只读

    class Meta:
        model = Course  # 写法和上面的CourseForm类似
        # exclude = ('id', ) # 注意元组中只有1个元素时不能写成("id")
        # fields = ('name', 'introduction', 'teacher', 'price')
        fields = "__all__"
        depth = 2  # 深度

3.4 Serializador de modelo hipervinculado con URL

Suponiendo que al solicitar información del curso, se espera que cada registro de información del curso pueda saltar a la página de detalles

Todas las configuraciones relacionadas con DRF están escritas en el diccionario REST_FRAMEWORK en settings.py
Heredado de
los campos HyperlinkedModelSerializer Add url
url es el valor predeterminado, si desea cambiarlo a otro nombre, como "enlace", puede establecer URL_FIELD_NAME en la configuración. py para usar Take effect globalmente

configuración.py

# DRF的全局配置
REST_FRAMEWORK = {
    
    
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',  # 自带分页类
    'PAGE_SIZE': 50,  # 每页数据量
    'DATETIME_FORMAT': '%Y-%m-%d %H:%M:%S',  # 时间显示格式
    'DEFAULT_RENDER_CLASSES': [
        'restframework.renders.JSONRenderer',
        'restframework.renders.BrowsableAPIRenderer',
    ],  # 返回response对象所用的类
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONparser',
        'rest_framework.parsers.Formparser',
        'rest_framework.parsers.MultiPartparser',
    ],  # 解析器,如何解析request请求中的request.data
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],  # 权限相关配置
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    ],  # 认证相关配置
    "URL_FIELD_NAME": 'link',
}

serializadores.py

class CourseSerializer(serializers.HyperlinkedModelSerializer):
    teacher = serializers.ReadOnlyField(source='teacher.username')  # 外键字段、只读

    class Meta:
        model = Course  # 写法和上面的CourseForm类似
        # url是默认值,可在settings.py中设置URL_FIELD_NAME使全局生效
        # fields = ('id', 'url', 'name', 'introduction', 'teacher', 'price', 'created_at', 'update_at')
        fields = ('id', 'link', 'name', 'introduction', 'teacher', 'price', 'created_at', 'update_at')

4.1 Las vistas de Django desarrollan una interfaz API RESTful

Use cuatro formas diferentes de interactuar con Restful API a través de DRF

  • programación funcional
  • vista de clase
  • Vista de clase genérica
  • Conjuntos de vistas para DRF

en el archivo vistas.py

4.1.1 Interfaz API de programación funcional vista nativa de Django

La idea es juzgar qué método es este y luego tratarlo.

@csrf_exempt
def course_list(request):
    course_dict = {
    
    
        'name': '课程名称',
        'introduction': '课程介绍',
        'price': 0.11
    }
    if request.method == "GET":
        # return HttpResponse(json.dumps(course_dict), content_type='application/json')
        return JsonResponse(course_dict) # 这两种写法是等价的
    if request.method == "POST":
        course = json.loads(request.body.decode('utf-8'))
        return JsonResponse(course, safe=False) # 如果解析的数据不是字典类型,是字符串的话,需要使用safe=false

Necesidad de prestar atención: solicitud de publicación, necesidad de usar el decorador para eliminar la restricción csrf

4.1.2 Interfaz API de programación de vista de clase de vista nativa de Django

La idea de escribir CBV es usar funciones correspondientes para procesar diferentes métodos de solicitud

import json

from django.http import JsonResponse, HttpResponse
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator

# Django CBV 编写API接口
@method_decorator(csrf_exempt, name='dispatch')
class CourseList(View):
    def get(self, request):
        return JsonResponse(course_dict)

    @csrf_exempt
    def post(self, request):
        course = json.loads(request.body.decode('utf-8'))
        return JsonResponse(course, safe=False)  # 如果解析的数据不是字典类型,是字符串的话,需要使用safe=false

El decorador de métodos se puede importar, y el método de decoración es envío, porque de acuerdo con el principio de respuesta de solicitud de django, cuando llega la solicitud, primero llega al método de envío y, después de ser procesada por el método de envío, encuentra el método de publicación.

Los dos métodos anteriores son para usar directamente Django nativo para escribir la interfaz, y hay muchas cosas que deben implementarse desde cero.
Tales como paginación, clasificación, autenticación, permisos, limitación actual, etc.
Luego hay una vista de DRF, que integra las funciones comunes de este desarrollo de interfaz.

4.2 DRF decorador api_view - programación funcional

4.2.1 Implementar la interfaz de "obtener toda la información del curso o agregar un nuevo curso"

  • Nueva vista fbv de drf
from rest_framework.decorators import api_view
from rest_framework.response import Response # django使用的是JsonResponse或HttpResponse,而drf直接封装好了,就是Response
from rest_framework import status
from .models import Course
from .serializers import CourseSerializer

"""一、函数式编程 Function Based View"""
@api_view(["GET", "POST"])
def course_list(request):
    """
    获取所有课程信息或新增一个课程
    :param request:
    :return:
    """
    if request.method == "GET":
        s = CourseSerializer(instance=Course.objects.all(), many=True) # 序列化多个对象,所以需要many=True
        # 序列化后的数据可以通过s.data获得
        return Response(data=s.data, status=status.HTTP_200_OK)
    elif request.method == "POST":
        s = CourseSerializer(data=request.data, partial=True) # 反序列化, partial=True表示部分更新
        if s.is_valid():
            s.save(teacher=request.user) # 讲师是只读属性
            return Response(data=s.data, status=status.HTTP_201_CREATED)
        return Response(s.erros, status=status.HTTP_400_BAD_REQUEST)

La programación funcional usará el decorador
Partial=True para indicar actualizaciones parciales.

  • nueva ruta

Para facilitar la gestión de rutas en la aplicación del curso, cree un archivo urls.py en la aplicación del curso y luego inclúyalo en las direcciones URL del proyecto mediante include
django urls include use

curso/urls.py

from django.urls import path
from course import views

urlpatterns = [
    # Function Based View
    path("fbv/list/", views.course_list, name="fbv-list")
]

drf_tutorial/urls.py

urlpatterns = [
    path('api-auth/', include('rest_framework.urls')), # DRF的登录退出
    path("admin/", admin.site.urls),
    path('course/', include('course.urls'))
]

inserte la descripción de la imagen aquí

La API de HyperlinkedModelSerializer no se usa primero, porque HyperlinkedModelSerializer es una clase de serialización altamente integrada, que se puede usar para programar con la vista drf configurada más adelante. Entonces, la clase serializadora usa en su lugar:

class CourseSerializer(serializers.ModelSerializer):
    teacher = serializers.ReadOnlyField(source='teacher.username')  # 外键字段、只读

    class Meta:
        model = Course  # 写法和上面的CourseForm类似
        # exclude = ('id', ) # 注意元组中只有1个元素时不能写成("id")
        # fields = ('name', 'introduction', 'teacher', 'price')
        fields = "__all__"
        depth = 2  # 深度
  • resultado devuelto
    inserte la descripción de la imagen aquí
  • solicitud de puesto de prueba
    inserte la descripción de la imagen aquí

4.2.2 Implementar la interfaz de "obtener información de un curso o actualizar y eliminar información de un curso"

  • Darse cuenta de la vista
@api_view(["GET", "PUT", "DELETE"])
def course_detail(request, pk): # 通过url传递pk
    """
    获取、更新、删除一个课程
    :param request:
    :param pk:
    :return:
    """
    try:
        course = Course.objects.get(pk=pk)
    except Course.DoesNotExist:
        return Response(data={
    
    "msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
    else:
        if request.method == "GET":
            s = CourseSerializer(instance=course) # 序列化一个对象不需要many=True
            return Response(data=s.data, status=status.HTTP_200_OK)

        elif request.method == "PUT": # PUT方法表示更新,部分写法和POST方法类似
            s = CourseSerializer(instance=course, data=request.data) #instance是指要序列化哪个实例,data表示数据哪里来的
            # 表示把data的数据,反序列化之后,保存或者更新到cuorse对象里
            if s.is_valid():
                s.save() # 不需要teacher字段
                return Response(s.data, status=status.HTTP_200_OK)

        elif request.method == "DELETE":
            course.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
  • implementar enrutamiento
urlpatterns = [
    # Function Based View
    path("fbv/list/", views.course_list, name="fbv-list")
    path("fbv/detail/<int:pk>", views.course_detail, name="fbv-detail")
]

4.3 Cómo usar Postman para probar la interfaz API (Soy apipost aquí)

Aquí tomo apipost como ejemplo

método de verificación:

  • autenticación de autenticación básica: nombre de cuenta, autenticación de contraseña

  • autenticación de clave api: autenticación de token
    inserte la descripción de la imagen aquí

  • OAuth 2.0, etc

Para agregar algunas claves y valores al encabezado de la solicitud, puede hacer clic en la
consulta del encabezado, que es un parámetro en la URL
. Los datos de la solicitud analizados en el código de back-end generalmente se colocan en bruto

  • Publicar solicitud
    inserte la descripción de la imagen aquí
  • Obtener solicitud
    inserte la descripción de la imagen aquí

4.4 Ver APIView en DRF - programación de vista de clase

4.4.1 Implementar la interfaz de "obtener toda la información del curso o agregar un nuevo curso"

  • importar APIView
from rest_framework.views import APIView
  • Implementar vista de clase
"""二、类视图 Class Based View"""
class CourseList(APIView):
    def get(self, request):
        """
        :param request:
        :return:
        """
        queryset = Course.objects.all()
        s = CourseSerializer(instance=queryset, many=True)
        return Response(s.data, status=status.HTTP_200_OK)

    def post(self, request):
        """
        :param request:
        :return:
        """
        s = CourseSerializer(data=request.data)
        if s.is_valid():
            s.save(teacher=self.request.user)
            print(type(request.data), type(s.data))
            # type(request.data): <class 'dict'>
            # type(s.data): <class 'rest_framework.utils.serializer_helpers.ReturnDict'>
            return Response(data=s.data, status=status.HTTP_201_CREATED)
        return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)
  • nueva ruta
urlpatterns = [
    # Function Based View
    path("fbv/list/", views.course_list, name="fbv-list"),
    path("fbv/detail/<int:pk>/", views.course_detail, name="fbv-detail"),

    # Class Based View
    path("cbv/list/", views.CourseList.as_view(), name='cbv-list')
]
  • solicitud de prueba
    inserte la descripción de la imagen aquí
    inserte la descripción de la imagen aquí

4.4.2 Implementar la interfaz de "página de detalles"

Método estático: ya sea que se llame directamente a través de un objeto de clase o un objeto de instancia, es posible llamarlo. Cabe señalar que los atributos y métodos de instancia no se pueden usar en métodos estáticos. Métodos estáticos, métodos de instancia y métodos de clase de
Python

  • implementar la interfaz
class CourseDetail(APIView):
    @staticmethod  # 静态方法
    def get_object(pk):
        """
        :param pk:
        :return:
        """
        try:
            return Course.objects.get(pk=pk)
        except Course.DoesNotExist:
            return

    def get(self, request, pk):
        """
        :param request:
        :param pk:
        :return:
        """
        obj = self.get_object(pk=pk)
        if not obj:
            return Response(data={
    
    "msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
        s = CourseSerializer(instance=obj)
        return Response(s.data, status=status.HTTP_200_OK)

    def put(self, request, pk):
        obj = self.get_object(pk=pk)
        if not obj:
            return Response(data={
    
    "msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
        s = CourseSerializer(instance=obj, data=request.data)
        if s.is_valid():
            s.save()
            return Response(data=s.data, status=status.HTTP_200_OK)
        return Response(s.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk):
        """
        :param request:
        :param pk:
        :return:
        """
        obj = self.get_object(pk=pk)
        if not obj:
            return Response(data={
    
    "msg": "没有此课程信息"}, status=status.HTTP_404_NOT_FOUND)
        obj.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)
  • implementar enrutamiento
urlpatterns = [
    # Function Based View
    path("fbv/list/", views.course_list, name="fbv-list"),
    path("fbv/detail/<int:pk>/", views.course_detail, name="fbv-detail"),

    # Class Based View
    path("cbv/list/", views.CourseList.as_view(), name='cbv-list'),
    path("cbv/detail/<int:pk>/", views.CourseDetail.as_view(), name='cbv-detail'),
]
  • solicitud de prueba
    inserte la descripción de la imagen aquí
    inserte la descripción de la imagen aquí
    inserte la descripción de la imagen aquí

El método de programación de vista de clases es casi el mismo que el método de programación funcional, y el código es casi el mismo. La siguiente sección explica una forma más concisa de escribir.

4.5 La vista de clase genérica GenericAPIView en DRF

importar genéricos

from rest_framework import generics

4.5.1 Realizar visualización y solicitud de nuevas interfaces

La vista general de clases en realidad mezcla las clases correspondientes a algunas operaciones comunes de adición, eliminación, modificación y consulta a través de mixin.
El nombre del atributo aquí está fijo.
Aquí debe sobrecargar el método perform_create.

4.5.2 Implementar la interfaz de detalles del curso

  • Implementar una vista de clase genérica

La siguiente escritura es equivalente a class GCourseDetail(generics.RetrieveUpdateDestroyAPIView):
pero para el siguiente método, el método de solicitud ya no es GET, PUT, PATCH, DELETE, sino recuperar, actualizar, destruir, etc., por lo que se recomienda utilizarclass GCourseDetail(generics.RetrieveUpdateDestroyAPIView):

from rest_framework import mixins
from rest_framework.generics import GenericAPIView


class GCourseDetail(generics.mixins.RetrieveModelMixin,
                                   mixins.UpdateModelMixin,
                                   mixins.DestroyModelMixin,
                                   GenericAPIView):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer
  • nueva ruta
urlpatterns = [
    # Function Based View
    path("fbv/list/", views.course_list, name="fbv-list"),
    path("fbv/detail/<int:pk>/", views.course_detail, name="fbv-detail"),

    # Class Based View
    path("cbv/list/", views.CourseList.as_view(), name='cbv-list'),
    path("cbv/detail/<int:pk>/", views.CourseDetail.as_view(), name='cbv-detail'),

    # Generic Class Based View
    path("gcbv/list/", views.GCourseList.as_view(), name='gcbv-list'),
    path("gcbv/detail/<int:pk>/", views.GCourseDetail.as_view(), name='gcbv-detail'),
]
  • solicitud de prueba
    inserte la descripción de la imagen aquí

Otras cosas se hacen en la vista de clase general: número total (recuento), página siguiente (siguiente), página anterior (anterior), datos (resultados)
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí

4.6 Interfaz de desarrollo de viewsets de DRF para agregar, eliminar, modificar y consultar información del curso - Viewset

  • importar conjuntos de vistas
from rest_framework import viewsets
  • crear conjunto de vistas
"""四、DRF的视图集"""
class CourseViewSet(viewsets.ModelViewSet):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer
    
    def perform_create(self, serializer):
        serializer.save(teacher=self.request.user)

Solo se requieren cuatro líneas de código sin autorización de autenticación

4.7 URL de Django y enrutadores DRF

  • nueva ruta

La forma de escribir es diferente a la
forma anterior de escribir las rutas de los dos conjuntos de vistas.

    • 1 escritura tradicional
    # DRF viewsets
    path("viewsets/", views.CourseViewSet.as_view(
        {
    
    "get": "list", "post": "create"}
    ), name="viewsets-list"),
    path("viewsets/<int:pk>/", views.CourseViewSet.as_view(
        {
    
    "get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destory"}
    ), name="viewsets-detail")
    • 2. Enrutadores de enrutamiento DRF
  • importar
from rest_framework.routers import DefaultRouter
router = DefaultRouter() # 把类实例化
router.register(prefix="viewsets", viewset=views.CourseViewSet) # 把视图集注册到这个路由实例里面

urlpatterns = [
    path("", include(router.urls))
]
  • interfaz de prueba
    inserte la descripción de la imagen aquí

5.1 Introducción a los métodos de autenticación DRF

Tres métodos de autenticación comúnmente utilizados en DRF:
1.BasicAuthentication: autenticación de nombre de usuario y contraseña
2.SessionAuthentication: autenticación de sesión
3.TokenAuthentication: autenticación de token
inserte la descripción de la imagen aquí

También puede implementar un esquema de autenticación personalizado, o usar un paquete de terceros, como json webtoken (sobre la autenticación jwt, que se explicará en el próximo curso práctico avanzado de drf).La diferencia entre autenticación y autoridad: la autenticación es la identidad del inicio de sesión
del usuario
Realizar verificación
El permiso se refiere a qué interfaces puede acceder un usuario que ha pasado la verificación de inicio de sesión; o para una interfaz determinada, qué nivel de datos puede obtener
De acuerdo con el proceso de respuesta de Django restframework a la solicitud http, la autenticación de identidad ocurre antes verificación de permisos y verificación de límite actual

Autenticación y permisos, el núcleo depende de dos datos: request.user, request.auth
El mecanismo de autenticación en realidad se basa en las múltiples clases de autenticación
en el marco de autenticación de Django
'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.TokenAuthentication', ],
, y DRF autenticará cada clase en orden de arriba a abajo. Y use la primera clase de autenticación aprobada con éxito para devolver el valor para establecer request.user y request.auth

5.1.1 Autenticación básica

Si se establece la autenticación básica, los encabezados tendrán una autorización adicional, que es el texto cifrado calculado por la biblioteca base64 del nombre de usuario y la contraseña, que el cartero completa automáticamente. La biblioteca base64 no es confidencial y se puede descifrar. Por lo tanto, la autenticación básica generalmente se usa para el trabajo de prueba, no para el entorno de producción.

  • Pruebe, después de pasar la autenticación de autenticación básica, qué devuelven request.user y request.auth
print(self.request.user, self.request.auth)
print(type(self.request.user), type(self.request.auth))
# admin None
# <class 'django.contrib.auth.models.User'> <class 'NoneType'>
  • Compruebe qué información hay en el encabezado de respuesta.
    La contraseña es correcta.
    inserte la descripción de la imagen aquí
    La contraseña es incorrecta.

Si la autenticación falla, habrá un campo WWW_Authenticate adicional en el encabezado de respuesta.
inserte la descripción de la imagen aquí

5.1.2 Autenticación de sesión

Se usa el backend de sesión predeterminado de Django. Por lo general, la autenticación de sesión se puede usar cuando se usan solicitudes HTTP y ajax en el front-end js. Al usar esto, se debe proporcionar un token csrf al backend.

5.1.3 Autenticación de Token

Es un método de autenticación http simple basado en token

  • Agregue INSTALLED_APPS en settings.py'rest_framework.authtoken'

generará una tabla de datos

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "rest_framework",  # 用于开发RESTful API
    'rest_framework.authtoken',  # DRF自带的Token认证
    'course.apps.CourseConfig',
]
  • La forma de generar token

5.1.3.1 Usar Django manag.py para generar Token

Solo lo pueden usar los administradores para probar
Generar tokens manualmente

python manage.py drf_create_token admin #给admin建一个token

inserte la descripción de la imagen aquí

5.1.3.2 Usando el mecanismo de señal de Django para generar Token

Propósito:
para generar tokens automáticamente,
los usuarios pueden solicitar tokens a través de la interfaz

ver.py

from django.db.models.signals import post_save # 保存之后,即用户已经建好之后的信号
from django.conf import settings
from django.dispatch import receiver # 接收信号
from rest_framework.authtoken.models import Token

@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def generate_token():

También puede importar directamente la clase de modelo de usuario de django como clase de modelo de autenticación: from django.contrib.auth.models import User
Principio: cuando una clase de modelo de usuario crea una nueva instancia y la guarda, es decir, cuando se crea un nuevo usuario, porque se llama al método save para guardar, el La señal post_save
se transmitirá al receptor, después de que el receptor acepte, ejecutará la función generar_token
Al ejecutar la función, la instancia se refiere a la instancia de usuario recién creada, created=True, por lo que se genera un registro en la tabla authtoken_token

¿Cómo puede el usuario obtener el token generado para el usuario?

rest_framework ha sido escrito para nosotros, podemos llamarlo directamente

En ruta total urls.py

from django.contrib import admin
from django.urls import path, include
from rest_framework.authtoken import views

urlpatterns = [
    path("api-token-auth/", views.obtain_auth_token), # 获取token的接口
    path('api-auth/', include('rest_framework.urls')), # DRF的登录退出
    path("admin/", admin.site.urls),
    path('course/', include('course.urls'))
]
  • Prueba: cree un nuevo usuario
    inserte la descripción de la imagen aquí
    user01 - mima123456
    inserte la descripción de la imagen aquí
    , puede ver que hay nuevos registros en la tabla de tokens
    inserte la descripción de la imagen aquí
  • Pruebe, obtenga token a través de la interfaz a través del cartero
    inserte la descripción de la imagen aquí

  • inserte la descripción de la imagen aquí
    Encabezado de solicitud de autenticación exitosa
print(self.request.user, self.request.auth)
print(type(self.request.user), type(self.request.auth))
# user01 e1e4eb90e389feb76c8bb71ad73e3b3c63e8090c
# <class 'django.contrib.auth.models.User'> <class 'rest_framework.authtoken.models.Token'>

Si la autenticación es exitosa, request.user sigue siendo una instancia de la clase de usuario de Django
request.auth es una instancia de la clase Token
y no hay información relacionada con la autenticación en el encabezado de respuesta.

  • Autenticación fallida
    inserte la descripción de la imagen aquí
  • Para usar un método de autenticación diferente para una determinada interfaz

No importa qué método de programación de vistas se utilice, existen métodos de configuración correspondientes. Los siguientes son cuatro métodos de programación de vista diferentes, que se explican por separado.

    • 1. Para la programación funcional
      , importe la clase de decoración para la autenticación:
from rest_framework.decorators import api_view, authentication_classes
from rest_framework.authentication import BasicAuthentication, SessionAuthentication, TokenAuthentication

Se ordenan decoradores

Un decorador de clase que solo agrega autenticación de contraseña al objeto

@api_view(["GET", "POST"])
@authentication_classes((BasicAuthentication, )) # 对象级别的认证设置,优先于全局设置
def course_list(request):
    """
    获取所有课程信息或新增一个课程
    :param request:
    :return:
    """
    if request.method == "GET":
        s = CourseSerializer(instance=Course.objects.all(), many=True)  # 序列化多个对象,所以需要many=True
        # 序列化后的数据可以通过s.data获得
        return Response(data=s.data, status=status.HTTP_200_OK)
    elif request.method == "POST":
        s = CourseSerializer(data=request.data, partial=True)  # 反序列化, partial=True表示部分更新
        if s.is_valid():
            s.save(teacher=request.user)  # 讲师是只读属性
            return Response(data=s.data, status=status.HTTP_201_CREATED)
        return Response(s.erros, status=status.HTTP_400_BAD_REQUEST)
  • prueba
    inserte la descripción de la imagen aquí

Presta atención a la redacción, debe serToken xxx


    • 2. Agregue atributos de clase directamente a la programación de vista de claseauthentication_classes
class CourseList(APIView):

    authentication_classes = (BasicAuthentication, SessionAuthentication, TokenAuthentication)

Lo mismo es cierto para las vistas de clases generales y los conjuntos de vistas, y también tienen atributos de clase.

5.3 Control de permisos DRF

¿Cuáles son las clases de permiso de uso común? ¿Cómo deben establecerse las políticas de permisos? ¿Cómo personalizar los permisos de nivel de objeto?

Los permisos de DRF están todos en el módulo de permisos. El proceso de verificación de permisos es el mismo que el de autenticación de identidad explicado anteriormente, y la información de autenticación de identidad en los atributos request.user y request.auth también se usa para determinar si la solicitud es aprobada en. ,

5.3.1 Las clases de permisos globales se pueden configurar en settings.py

inserte la descripción de la imagen aquí

  • Las clases de permisos comunes son:

IsAuthenticatedOrReadOnly: los usuarios registrados pueden agregar, eliminar, modificar y consultar, y los usuarios no registrados pueden consultar
IsAuthenticated: solo los usuarios registrados pueden realizar todas las operaciones, los usuarios no registrados no pueden realizar todas las operaciones y obtener no funciona. IsAdminUser
: los usuarios administradores tienen permiso para acceder a la interfaz, ¿verdad? El administrador mira el campo is_staff de la tabla auth_user, verdadero significa que es un usuario de nivel administrador
AllowAny: Permitir todas las solicitudes

5.3.2 Cómo establecer permisos a nivel de interfaz/objeto

  • decorador de importación
from rest_framework.decorators import api_view, authentication_classes, permission_classes
  • Clase de permiso de importación
在这里插入代码片

5.3.2.1 Establecer permiso para la vista de funciones

  • Agregar un decorador a la vista de funciones
@api_view(["GET", "POST"])
@authentication_classes((BasicAuthentication, ))  # 对象级别的认证设置,优先于全局设置
@permission_classes((IsAuthenticated, )) # 自定义的权限类
def course_list(request):

5.3.2.2 Configuración de permisos para vistas de clase/vistas de clase generales/conjuntos de vistas

  • directamente en el atributo de claseauthentication_classes
permission_classes = (IsAuthenticated, )

5.3.3 ¿Cómo personalizar los permisos a nivel de objeto?

La implementación solo puede modificar su propia información, y la información de otras personas solo se puede ver, no modificar.

  • Cree permiso.py en la aplicación y cree una clase de permiso personalizada
    permiso.py
class IsOwnerReadOnly(permissions.BasePermission):
    """
    自定义权限:只有对象的所有者可以增删改查
    """

    def has_object_permission(self, request, view, obj):  # 重写BasePermission的方法
        """
        所有的request请求都有读权限,因此一律允许GET/HEAD/OPTIONS方法
        如果用户是自己,可以修改
        :param request:
        :param view:
        :param obj:
        :return: bool
        """
        if request.method in permissions.SAFE_METHODS:
            return True
        # 对象的所有者才有写权限
        return obj.teacher == request.user

has_object_permissionMétodos anulados
Los métodos seguros ("GET", "HEAD", "OPTIONS")se pueden permissions.SAFE_METHODSreemplazar con

inserte la descripción de la imagen aquí

  • Importe la clase de permiso personalizada creada en la vista
from .permission import IsOwnerReadOnly

class GCourseList(generics.ListCreateAPIView):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer
    permission_classes = (IsAuthenticated, )

    def perform_create(self, serializer):
        serializer.save(teacher=self.request.user)


class GCourseDetail(generics.RetrieveUpdateDestroyAPIView):
    queryset = Course.objects.all()
    serializer_class = CourseSerializer
    permission_classes = (IsAuthenticated, IsOwnerReadOnly)
  • interfaz de prueba
    inserte la descripción de la imagen aquí
    inserte la descripción de la imagen aquí

6.1 Cómo generar documentos de interfaz API

6.1.1 Cómo generar documentos de interfaz API

Puede ver el formato y otra información de una sola interfaz solicitando la url. Pero, ¿hay alguna manera de mostrar toda la información de la interfaz, es decir, la documentación en línea de la API,
para que el front-end pueda verla fácilmente y quede claro de un vistazo?
Las siguientes operaciones primero debenpip install coreapi

  • 1. Agregar a REST_FRAMEWORK de settings.py
REST_FRAMEWORK = {
    
    
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema',
    ...
    }
  • 2. Agregue el enrutamiento en el total de urls.py,
    primero importe get_schema_view
    y luego cree la instancia get_schema_view
    y luego cree el enrutamiento
from rest_framework.schemas import get_schema_view

schema_view = get_schema_view(title="DRF API文档", description="xxx")

urlpatterns = [
    path("api-token-auth/", views.obtain_auth_token), # 获取token的接口
    path('api-auth/', include('rest_framework.urls')), # DRF的登录退出
    path("admin/", admin.site.urls),
    path('course/', include('course.urls')),
    path('schema/', schema_view),
]
  • prueba
    inserte la descripción de la imagen aquí

Se recomienda descargar el complemento jsonView en Chrome App Store

Haga clic en GET-corejson
inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

Pero el documento aún no es lo suficientemente hermoso, la siguiente sección presenta la función general de usar coreapi

6.2 Introducción al uso general de DRF

Cómo se debe configurar coreapi y cómo utilizar el documento.

  • Modifique la propiedad 'DEFAULT_SCHEMA_CLASS' de REST_FRAMEWORK
    inserte la descripción de la imagen aquí
  • en urls.py
    • 1. Importar el módulo y agregar una nueva ruta
from rest_framework.documentation import include_docs_urls

urlpatterns = [
    path("api-token-auth/", views.obtain_auth_token),  # 获取token的接口
    path('api-auth/', include('rest_framework.urls')),  # DRF的登录退出
    path("admin/", admin.site.urls),
    path('docs/', include_docs_urls(title='DRF API文档', description='Django REST framework快速入门')),
    path('course/', include('course.urls')),
]
  • prueba
    inserte la descripción de la imagen aquí

En este documento de API, después de configurar la autenticación, debe volver a configurarse después de actualizar

7.1 Resumen del curso

  • ¿Qué desarrollo de vista se debe usar?
    Use la vista funcional para escribir de manera flexible, pero esta es una forma orientada al proceso y la tasa de repetición es alta.
    Usando la vista de clase, puede usar las características de las clases en python, encapsulación, herencia, polimorfismo y reducir la repetición de código. Clase general La vista es más
    flexible Bajo
    El conjunto de vistas es altamente personalizado y la flexibilidad es mínima
    En general, la programación de vista de clases es el método principal.

  • ¿Cómo funciona DRF? Código fuente APIView? ¿prueba? ¿cache? limitando . . no hablé de eso

Supongo que te gusta

Origin blog.csdn.net/zhangyifeng_1995/article/details/131898576
Recomendado
Clasificación