ahzhu

导航

PYTHON

\PYTHON

异常

在 Python 3 中处理异常也轻微的改变了,在 Python 3 中我们现在使用 as 作为关键词。

捕获异常的语法由 except exc, var 改为 except exc as var

使用语法except (exc1, exc2) as var 可以同时捕获多种类别的异常。 Python 2.6 已经支持这两种语法。

    1. 在 2.x 时代,所有类型的对象都是可以被直接抛出的,在 3.x 时代,只有继承自BaseException的对象才可以被抛出。
    1. 2.x raise 语句使用逗号将抛出对象类型和参数分开,3.x 取消了这种奇葩的写法,直接调用构造函数抛出对象即可。

在 2.x 时代,异常在代码中除了表示程序错误,还经常做一些普通控制结构应该做的事情,在 3.x 中可以看出,设计者让异常变的更加专一,只有在错误发生的情况才能去用异常捕获语句来处理。

Python列表

List(列表) 是 Python 中使用最频繁的数据类型。

列表可以完成大多数集合类的数据结构实现。它支持字符,数字,字符串甚至可以包含列表(即嵌套)。

列表用 [ ] 标识,是 python 最通用的复合数据类型。

列表中值的切割也可以用到变量 [头下标:尾下标] ,就可以截取相应的列表,从左到右索引默认 0 开始,从右到左索引默认 -1 开始,下标可以为空表示取到头或尾。

Python 元组

元组是另一个数据类型,类似于 List(列表)。

元组用 () 标识。内部元素用逗号隔开。但是元组不能二次赋值,相当于只读列表。

字典键的特性

字典值可以没有限制地取任何 python 对象,既可以是标准的对象,也可以是用户定义的,但键不行。

两个重要的点需要记住:

1)不允许同一个键出现两次。创建时如果同一个键被赋值两次,后一个值会被记住,如下实例:

实例

#!/usr/bin/python tinydict = {'Name': 'Runoob', 'Age': 7, 'Name': 'Manni'} print "tinydict['Name']: ", tinydict['Name']

以上实例输出结果:

tinydict['Name']:  Manni

2)键必须不可变,所以可以用数字,字符串或元组充当,所以用列表就不行,如下实例:

实例

#!/usr/bin/python tinydict = {['Name']: 'Zara', 'Age': 7} print "tinydict['Name']: ", tinydict['Name']

参数传递

在 python 中,类型属于对象,变量是没有类型的:

a=[1,2,3] a="Runoob"

以上代码中,[1,2,3] 是 List 类型,"Runoob" 是 String 类型,而变量 a 是没有类型,她仅仅是一个对象的引用(一个指针),可以是 List 类型对象,也可以指向 String 类型对象。

可更改(mutable)与不可更改(immutable)对象

在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。

  • 不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
  • 可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

python 函数的参数传递:

  • 不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
  • 可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响

python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

DJANGO

创建APP

终端指令:

python manage.py startapp app01(app名称)
python manage.py migrate

API编写

RESTful(Representational State Transfer)架构风格是一种广泛采用的网络应用程序架构,主要用于构建灵活、可扩展且意义明确的Web API。REST是一组设计原则和约定,而不是标准,因此它可以根据具体的应用需求灵活实现。下面是RESTful API设计的主要规范和特点:

1. 资源识别

在RESTful架构中,每个资源都有一个唯一的标识符,通常是URI(统一资源标识符)。资源表示某种实体或数据集,如用户、订单等。

2. 表述性

资源有多种表现形式,如JSON、XML等。客户端和服务器通过HTTP协议交换这些表现形式,使得API具有自描述性。

3. 无状态

每个请求从客户端到服务器必须包含所有执行请求所需的信息。服务器不存储关于客户端的任何状态信息,这使得RESTful服务更易于扩展。

4. 可操作的资源

RESTful API通过标准HTTP方法对资源进行操作。这些方法包括:

  • GET:检索资源。
  • POST:创建新资源。
  • PUT:更新现有资源。
  • DELETE:删除资源。

5. 统一接口

RESTful API应该具有统一且一致的接口,这有助于减少学习成本,提高可理解性。接口的统一性也意味着API的可预测性和可插拔性。

6. 超媒体作为应用状态的引擎(HATEOAS)

超媒体链接是REST架构的核心概念之一。响应中应包含足够的信息(如链接),让客户端能够发现其他相关的操作或资源。这种设计使得客户端可以通过服务器提供的动态链接导航API。

7. 分层系统

REST架构通常是分层的,客户端通常不知道它是直接与最终服务器通信,还是与中间层(如代理、负载均衡器)通信。这种分层架构有助于提高API的可扩展性和安全性。

实例应用

举例来说,一个简单的RESTful API可能包括以下HTTP请求和响应:

  • GET /users:返回所有用户列表。
  • POST /users:创建一个新用户。
  • GET /users/123:返回ID为123的用户详情。
  • PUT /users/123:更新ID为123的用户。
  • DELETE /users/123:删除ID为123的用户。

这种风格的API易于理解和使用,并且可以利用现有的广泛使用的HTTP协议。由于其无状态和可扩展的特性,RESTful API非常适合构建大型、分布式的Web应用。

pip install djangorestframework

restframework本质上是app

因此需要在setting中注册

INSTALLED_APPS = [
    # "django.contrib.admin",
    # "django.contrib.auth",
    # "django.contrib.contenttypes",
    # "django.contrib.sessions",
    # "django.contrib.messages",
    "django.contrib.staticfiles",
    #注册
    "rest_framework"
]
urlpatterns = [
    # path("admin/", admin.site.urls),
    path("auth/", views.auth),
    path("login/", views.login),
    path("info/", views.InfoView.as_view())
]
from django.http import JsonResponse
from rest_framework.response import Response

from rest_framework.decorators import api_view
from rest_framework.views import APIView


# Create your views here.

def auth(request):
    """
    This is a view function that returns a JsonResponse object.
    :param request:
    :return:
    """
    return JsonResponse({"status": True, "message": "success"}, )


@api_view(["GET"])
def login(request):
    """
    This is a view function that returns a JsonResponse object.
    :param request:
    :return:
    """
    return Response({"status": True, "message": "success"}, )


# 第二种写法
class InfoVIew(APIView):
    def get(self, request):
        return Response({"status": True, "message": "success"}, )

image-20240419205316801

image-20240419210121507

实际开发中一般是基于类方式,既第二种方式

xxxxxxxxxx $ sudo service ssh --full-restarttext

函数视图 (Function-Based Views, FBV)

函数视图 是一种直接使用 Python 函数来处理视图逻辑的方式。这种方式的代码通常比较直接,适用于简单的视图逻辑。

优点:

  • 简单直观,容易理解和使用。
  • 控制流程清晰,适合处理简单的逻辑。

缺点:

  • 当视图逻辑变得复杂时,代码会变得冗长和难以维护。
  • 代码复用性较低。

示例:

from django.http import JsonResponse
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status

@api_view(['GET', 'POST'])
def book_list(request):
    if request.method == 'GET':
        books = Book.objects.all()
        serializer = BookSerializer(books, many=True)
        return Response(serializer.data)
    elif request.method == 'POST':
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

类视图 (Class-Based Views, CBV)

类视图 则是使用 Python 类来处理视图逻辑。Django REST Framework 提供了许多内建的类视图,如 ListAPIViewRetrieveAPIView 等,使得处理常见的数据操作变得更简洁。

优点:

  • 高度可重用,通过继承和混入(Mixin)可以轻松扩展功能。
  • 结构化良好,适合处理复杂逻辑和大型项目。

缺点:

  • 初学者可能需要时间适应其抽象性。
  • 灵活性稍逊于函数视图。

示例:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.shortcuts import get_object_or_404

class BookList(APIView):
    def get(self, request):
        books = Book.objects.all()
        serializer = BookSerializer(books, many=True)
        return Response(serializer.data)

    def post(self, request):
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

两种方式各有所长,你可以根据项目的具体需求和个人偏好选择适合的方式来实现视图逻辑。

request对象

在 Django REST Framework(DRF)中,request 对象是对 Django 的原生 HttpRequest 对象的扩展。这个扩展的 Request 对象提供了更多功能,特别是对于处理 API 请求非常有用。以下是 DRF 中 request 对象的主要特性和功能:

1. 请求数据解析

DRF request 对象可以处理多种内容类型的请求数据,包括 JSON、表单数据等。通过请求对象的 .data 属性,你可以访问到解析后的请求体数据。与 Django 的 HttpRequest 中的 .POST.FILES 等属性不同,.data 属性适用于所有类型的请求体。

# 在视图中访问请求数据
def post(self, request):
    print(request.data)  # 打印解析后的请求体数据
    return Response({'status': 'received'}, status=200)

2. 查询参数

request 对象的 .query_params 属性提供了对查询字符串参数的访问。这相当于 Django 的 HttpRequest 对象中的 .GET 属性。

def get(self, request):
    search_term = request.query_params.get('search', None)
    if search_term:
        # 基于查询参数执行一些操作
        pass
    return Response({'status': 'ok'})

3. HTTP方法

通过 request.method 属性,可以检查请求的 HTTP 方法(如 GET、POST 等),使得在视图中根据不同的方法执行不同的逻辑成为可能。

4. 用户认证

DRF 通过 request.user 属性提供了对当前经过认证的用户的访问。如果用户未认证,此属性通常是 AnonymousUser 类型的实例。

def get(self, request):
    if request.user.is_authenticated:
        return Response({'status': 'You are authenticated'})
    return Response({'status': 'Please log in'}, status=401)

5. 权限和节流

在 DRF 视图中,可以利用 request 对象来判断请求是否具有执行特定操作的权限或是否受到节流控制。

6. 更多属性和方法

DRF 的 request 对象还包含有关请求的其他信息,如 request.auth(提供认证信息)和 request.content_type(请求体的内容类型)。

总的来说,DRF 的 request 对象大幅增强了开发者处理 HTTP 请求的能力,特别是在构建 RESTful API 时,提供了更多便利和控制。这些功能让开发者能够专注于业务逻辑的实现,而不是低级的请求解析和数据处理。

认证组件

在 Django REST Framework(DRF)中,认证组件是核心功能之一,用于确定请求是否来自合法的用户,并对用户身份进行验证。DRF 提供了多种认证机制,可以灵活地配置和扩展以适应不同的安全需求。以下是一些常见的认证方法及其用途:

1. 基本认证(Basic Authentication)

这是最简单的认证方式,基于 HTTP 标准中的 Basic Authentication。它通过 HTTP 头部传递用户名和密码(Base64 编码)进行认证。虽然实现简单,但由于传递的凭据未加密,因此不建议在生产环境中使用,除非配合 HTTPS 使用。

2. 令牌认证(Token Authentication)

在这种方式中,系统在用户初次登录时生成一个令牌(Token),之后的每个请求都必须在其 HTTP 头部携带这个令牌进行认证。这种方式比基本认证安全,适合用于客户端和服务端之间的无状态交互,常见于移动应用和单页应用(SPA)。

3. 会话认证(Session Authentication)

这种认证利用 Django 的会话框架进行用户认证,适合用在浏览器客户端。用户的身份信息存储在服务器的会话中,客户端通过 cookie 来维持会话状态。这种方式允许使用 Django 的 CSRF 保护机制,增强安全性。

4. JWT(JSON Web Token)认证

JSON Web Tokens 是一种广泛使用的认证策略,它允许服务器生成一个 JSON 对象,密封并传递给客户端。客户端随后的请求将这个 Token 发回服务器进行身份验证和用户信息的读取。JWT 是自包含的,可以包含所有用户验证所需的信息。

在 Django REST Framework (DRF) 中,如果你希望在所有的视图中使用相同的认证方式,而不是在每个视图中单独设置 authentication_classes,你可以通过修改项目的全局配置来实现。这可以在项目的设置文件(通常是 settings.py)中进行配置。

全局配置认证类

以下是如何全局配置自定义的 MyAuth 认证类的步骤:

  1. 确保自定义认证类已正确实现

    确保你的 MyAuth 类已经被定义并且实现了所需的认证逻辑。

    #全局配置的时候配置组件不能写在views.py文件
    class MyAuth(BaseAuthentication):
        def authenticate(self, request):
            # 1. 获取用户认证,读取发送请求时的token
            token = request.query_params.get("token")
            # 2. 校验token合法性
            if token:
                return ("zxw", token)
            raise AuthenticationFailed({"code": 1001, "error": "认证失败"})
    
            # 3. 关于返回值
            #  3.1 如果合法,返回元组(用户,token)
            #  3.2 如果不合法,返回错误信息
            #  3.3 如果没有认证信息,返回None  ---多个认证类时[类1,类2,类3],返回None,会继续执行下一个认证类,若都没用户信息,返回匿名用户
    
  2. 修改全局配置

    drf优先从全局寻找再从视图中选取

    在项目的 settings.py 文件中,找到或添加 REST_FRAMEWORK 配置字典,并设置 DEFAULT_AUTHENTICATION_CLASSES 到你的自定义认证类。

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'myapp.authentication.MyAuth',  # 替换为你的模块和类名
    ),
}

在这个配置中,'myapp.authentication.MyAuth' 应该被替换为你的认证类的实际导入路径。例如,如果你的 MyAuth 类定义在 myapp/authentication.py 文件中,那么上述路径应该是正确的。

效果

设置了全局认证类后,所有视图默认使用这些认证类,除非在视图级别显式指定了其他认证类。这意味着你不需要在每个视图中重复写 authentication_classes = [MyAuth]

覆盖全局认证
如果有特定的视图你不想使用全局认证,或者想使用不同的认证方式,你可以在那个视图中显式设置 authentication_classes。例如:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.authentication import SessionAuthentication

class SpecialView(APIView):
    authentication_classes = [SessionAuthentication]  # 只为这个视图使用会话认证

    def get(self, request):
        return Response({"message": "This view uses session authentication."})

在这个例子中,尽管全局配置使用了 MyAuthSpecialView 仍然只使用 SessionAuthentication

通过这种方式,DRF 提供了极高的灵活性和便利性,让你能够轻松地管理和配置认证方式,满足不同视图和应用场景的需要。

多个认证类

----都返回None,都没用认证成功-》视图是否会执行?视图函数会执行,只不过self.user self.auth = None

image-20240422111305498

一个是请求体参数,一个url传递的参数

认证组件=[认证类,认证类,认证类。。。。] ->执行每一个认证类中的authentication方法:

​ -认证成功或失败,不会执行后续认证类

​ -返回None,执行后续认证类

权限组件

权限组件=[权限类,权限类,权限类。。。。] ->执行所有权限类中的has_permisson方法,返回TRUE通过,返回FALSE表示不通过

​ -

​ 默认情况下,保障所有权限类中的has_permisson方法都返回TRUE

解析器

  1. 读取请求头
  2. 依据请求头解析数据
    1. 依据请求头获取解析器-->JSON解析器
    2. request.data = JSON解析器.parse
  3. request.data

元类

序列化器

在views.py中定义类,注意提前在 models.py定义好模型类。fields = ["xxx","xxx"]可以指定字段

class DepartSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Depart
        fields = "__all__"
        
fields = ["xxx","xxx"]

也可以这样

class DepartSerializer(serializers.ModelSerializer):
    title = serializers.CharField()
    order = serializers.IntegerField()
    count = serializers.IntegerField()

之后即可使用序列化器

class DepartView(APIView):
    def get(self, request, *args, **kwargs):
        # 数据库获取数据
        query_set = models.Depart.objects.all()

        # 转换JSON格式 -序列化器,多个对象的时候many = True
        serializer = DepartSerializer(instance=query_set,many=True)
        print(serializer.data)

        # 返回Response
        return Response(serializer.data)

字段显示可以定制:

class UserInfoSerializer(serializers.ModelSerializer):
    gender_text = serializers.CharField(source="get_gender_display")
    depart_text = serializers.CharField(source="depart.title")
    ctime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")

    xxx = serializers.SerializerMethodField()

    class Meta:
        model = models.UserInfo

        fields = ["name", "age", "gender", "gender_text","depart_text","ctime","xxx"]

    def get_xxx(self, obj):
        return "xxx"



嵌套

当user有多对多属性tag的时候,并且tag也是一张表。可以手动序列化tag属性(存在嵌套关系)

class UserInfoSerializer(serializers.ModelSerializer):
    gender_text = serializers.CharField(source="get_gender_display")
    depart_text = serializers.CharField(source="depart.title")
    ctime = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")

    xxx = serializers.SerializerMethodField()

    class Meta:
        model = models.UserInfo

        fields = ["name", "age", "gender", "gender_text","depart_text","ctime","xxx"]

    def get_xxx(self, obj):
        result = []
        query_srt = obj.tag.all()

        for tag in query_srt:
            result.append({"id":tag.id, "title": tag.title})

        return result

数据校验

路由-视图-request.data-校验-操作

class DepartView(APIView):


    # 新增数据
    def post(self, request, *args, **kwargs):

        # 校验
        serializer = DepartSerializer(data=request.data)
        if serializer.is_valid():
            print(serializer.validated_data)
            return Response(serializer.validated_data)
        else:
            print(serializer.errors)
            return Response(serializer.errors)
        # 也可写成 serializer.is_valid(raise_exception=True)

在 Django REST Framework(DRF)中,内置的校验主要是通过字段类型(如 CharField, IntegerField, EmailField 等)自动应用的,而正则表达式校验可以通过 RegexField 或在任何字段上使用 validators 参数来实现。

内置校验示例

下面是一个使用 DRF 内置校验的简单序列化器示例,其中包括了字符字段和电子邮件字段的校验:

from rest_framework import serializers

class UserSerializer(serializers.Serializer):
    name = serializers.CharField(max_length=100)  # 内置校验,确保输入是字符类型且长度不超过100
    email = serializers.EmailField()  # 内置校验,确保输入符合电子邮件格式

在这个例子中:

  • CharField 自动校验数据是字符串类型,并且长度不超过指定的 max_length
  • EmailField 自动校验输入的是有效的电子邮件地址格式。
正则表达式校验示例

如果你需要对输入数据进行更具体的格式校验,可以使用 RegexField 或在任何字段上添加正则表达式校验器:

from rest_framework import serializers
from rest_framework.validators import RegexValidator

class UserProfileSerializer(serializers.Serializer):
    username = serializers.CharField(
        validators=[RegexValidator(regex='^[a-zA-Z0-9]*$', message='用户名只能包含字母和数字。')]
    )
    phone_number = serializers.RegexField(regex=r'^\+?1?\d{9,15}$', error_messages={
        'invalid': '电话号码格式不正确。'
    })

在这个例子中:

  • username 字段使用了 RegexValidator,该校验器确保用户名只包含字母和数字。
  • phone_number 字段使用了 RegexField,直接在字段定义中指定了正则表达式,用于校验国际电话号码格式。

这两种方式都可以通过正则表达式来限定字段的有效输入,从而实现更精确的数据校验需求。

总结

通过使用 DRF 的内置字段和正则表达式校验,你可以有效地控制和验证通过你的 API 接收的数据,确保它们符合预期格式和业务逻辑要求。这些工具提供了灵活性和强大的数据验证能力,有助于保护你的应用免受无效或恶意数据的影响。

钩子校验

在 Django REST Framework (DRF) 中,"钩子校验"(Hook Validation)通常指的是在序列化器中利用特定的方法来实现自定义校验逻辑的机制。这些方法通常被称为 "验证钩子"(Validation Hooks)。这些钩子使得开发者能够在数据保存之前插入自定义的验证逻辑,从而增强数据校验的灵活性和力度。

常见的验证钩子

DRF 提供了几种不同类型的验证钩子,最常见的包括:

  1. 字段级验证方法:这些方法用于对单个字段进行校验,方法名以 validate_<fieldname> 的形式命名。这类方法接收单个字段的值作为参数,返回校验后的值或抛出 serializers.ValidationError

  2. 对象级验证方法:这是一个特殊的方法 validate,用于在对象级别进行校验。该方法接收所有已经进行初步校验的数据的字典,可以对字段间的依赖关系进行校验,最后返回整理后的数据字典。

示例:字段级和对象级验证

假设我们有一个序列化器用于用户注册,需要验证用户名不仅符合格式要求,还要确保不重复(假设数据库层面没有设置唯一性约束)。

from rest_framework import serializers

class SignupSerializer(serializers.Serializer):
    username = serializers.CharField(max_length=100)
    password = serializers.CharField(max_length=100)
    confirm_password = serializers.CharField(max_length=100)

    def validate_username(self, value):
        """
        检查用户名是否已存在。
        """
        if User.objects.filter(username=value).exists():
            raise serializers.ValidationError("用户名已被占用。")
        return value

    def validate(self, data):
        """
        检查密码和确认密码是否匹配。
        """
        if data['password'] != data['confirm_password']:
            raise serializers.ValidationError("密码和确认密码不匹配。")
        return data

在这个例子中:

  • validate_username 方法是一个字段级验证钩子,用于确保用户名是唯一的。
  • validate 方法是一个对象级验证钩子,用于确保密码和确认密码是一致的。

通过这些验证钩子,你可以在数据持久化前进行细致的校验,确保数据的正确性和业务规则的遵守。

总结

钩子校验在 DRF 中是一个非常强大的特性,允许开发者对数据进行深入的自定义校验,确保通过 API 接收和处理的数据既安全又有效。

model校验

在 Django REST Framework (DRF) 中,模型校验主要涉及两个层面:通过 Django 模型本身实现的校验以及在 DRF 序列化器中实现的额外校验。虽然 DRF 依赖于 Django 的模型校验系统,但它还提供了一系列工具和方法,使得在序列化器层面进行数据校验变得更加灵活和强大。与serializers.Serializer相比,model校验中可以直接操作数据库,不需要写额外的代码。

DRF 中的模型校验
  1. 使用 Django 的内置模型校验

    • 如之前所述,Django 模型可以通过定义 clean() 方法以及在字段定义中使用内置校验器(如 max_lengthunique 等)来进行校验。这些校验可以通过在 DRF 序列化器中显式调用 full_clean() 方法来激活。这通常在序列化器的 create()update() 方法中进行。
  2. 在序列化器中进行校验

    • DRF 允许在序列化器级别定义字段级和对象级校验规则,这些校验规则可以补充或覆盖 Django 模型的校验逻辑。例如,使用 validate_<fieldname>() 方法进行字段级校验或 validate() 方法进行整体数据校验。
示例:整合 Django 模型校验与 DRF 序列化器

假设有一个简单的 Event 模型,并在 DRF 序列化器中整合模型校验:

from django.core.exceptions import ValidationError
from django.db import models
from rest_framework import serializers

class Event(models.Model):
    title = models.CharField(max_length=100)
    start_datetime = models.DateTimeField()
    end_datetime = models.DateTimeField()

    def clean(self):
        if self.start_datetime >= self.end_datetime:
            raise ValidationError("结束时间必须在开始时间之后。")

class EventSerializer(serializers.ModelSerializer):
    class Meta:
        model = Event
        fields = ['title', 'start_datetime', 'end_datetime']

    def validate(self, data):
        # 调用模型的 full_clean 方法来执行 Django 层面的校验
        instance = Event(**data)
        instance.clean()
        return data

在这个示例中:

  • 模型的 clean() 方法定义了一个校验规则,确保事件的结束时间在开始时间之后。
  • 序列化器的 validate() 方法创建了一个临时实例并调用了 clean(),这样就在序列化器中触发了模型的校验逻辑。这种方法确保了在数据保存前模型的校验规则被执行。
注意事项
  • 性能考虑:在序列化器中频繁调用模型的 clean() 方法可能影响性能,尤其是在数据量大或校验逻辑复杂的情况下。
  • 校验覆盖:确保 DRF 序列化器中的校验规则与 Django 模型校验不冲突,并合理覆盖所有需要的业务规则。

总结来说,DRF 中的模型校验是通过结合 Django 模型的内置校验和序列化器的灵活校验规则来实现的。这种结合方式提供了强大的数据保护机制,确保了通过 API 接收和处理的数据的有效性和一致性。


案例
class UsModelSerializer(serializers.ModelSerializer):
    # more = serializers.CharField(required=True)

    class Meta:
        model = models.UserInfo
        fields = ["name", "gender","depart", "tag"]
        extra_kwargs = {
            "name": {"validators": [RegexValidator(regex=r'^[\u4e00-\u9fff]+$', message="名字必须全部是中文字符")]}
        }

    def validate_depart(self, value):
        if value.id > 1:
            return value
        raise exceptions.ValidationError("部门错误")
class UsView(APIView):
    def get(self, request, *args, **kwargs):
        return Response({"message": "Hello, World!"})

    def post(self, request, *args, **kwargs):
        ser = UsModelSerializer(data=request.data)
        if ser.is_valid():
            print(ser.validated_data)
            ser.save()

        else:
            print(ser.errors)
        return Response({"message": "成功!"})

序列化和校验可以分别用两个序列化器,也可以都用同一个序列化器

在Django REST Framework中,serializers.CharField定义了一个序列化字段,用于处理文本数据。这个字段可以在序列化器中用来表示模型的一个字符串属性。字段的参数read_only=Truewrite_only=True提供了字段的额外配置选项:

  • read_only=True:这个设置意味着字段仅用于序列化输出。也就是说,当你从数据库获取数据并将其发送给客户端时,这个字段会被包括在内,但在从客户端接收数据并保存到数据库时,这个字段不会被考虑。
  • write_only=True:这个设置意味着字段仅用于反序列化输入。也就是说,这个字段可以接收客户端数据并保存到数据库,但在将数据发送回客户端时,它不会被包括在响应中。

然而,同时设置read_only=Truewrite_only=True是互斥的,这在实际应用中没有意义,因为这会使字段既不能读也不能写,这通常是一个配置错误。你应该根据字段的用途选择其中一个设置

class DpModelSerializer(serializers.ModelSerializer):
    v1 = serializers.CharField(read_only=True,write_only=True)
    class Meta:
        model = models.Depart
        fields = "__all__"

自定义钩子推荐方法:

在 Django REST Framework(DRF)中,to_representation 方法是序列化器中一个关键的自定义方法,允许你详细控制如何将模型实例转换为最终的序列化数据格式。这个方法通常用于定制输出的数据结构,适应复杂的数据表示需求。

工作原理

to_representation 方法在序列化器将模型数据转换为字典格式(通常用于返回给客户端的JSON数据)时调用。该方法接收一个模型实例作为输入,并返回一个代表该实例序列化形式的字典。

用途

to_representation 方法在序列化器将模型数据转换为字典格式(通常用于返回给客户端的JSON数据)时调用。该方法接收一个模型实例作为输入,并返回一个代表该实例序列化形式的字典。

使用 to_representation 方法可以进行以下操作:

  • 添加额外信息:在序列化输出中添加不直接存储在数据库模型中的信息。

  • 修改字段表示:改变某些字段的序列化方式,例如日期格式化、合并多个字段等。

  • 条件过滤数据:根据特定条件排除一些字段或数据,例如基于用户权限过滤敏感信息。

  • 示例代码

    假设有一个 Book 模型,我们想在序列化输出中添加一个计算字段 is_new,该字段表示图书是否为新发布(发布不超过30天):

from django.utils import timezone
from rest_framework import serializers
from datetime import timedelta

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['id', 'title', 'release_date']
        
    def to_representation(self, instance):
    representation = super().to_representation(instance)
    # 添加一个计算字段 'is_new',表示书籍是否是新书
    representation['is_new'] = (timezone.now() - instance.release_date) <= timedelta(days=30)
    return representation
        

在 Django REST Framework (DRF) 中,序列化器(Serializer)通常用来将复杂数据类型转换为 Python 数据类型,然后再转换为 JSON,XML 或其他内容类型,以便于网络传输。serializers.ModelSerializerserializers.Serializer 是两种基础的序列化器类,它们有不同的使用场景和功能。

serializers.ModelSerializer

ModelSerializer 类是为 Django 模型(models)定制的,它自动地根据模型字段生成相应的序列化器字段。例如,如果模型字段是 CharFieldModelSerializer 会自动使用 serializers.CharFieldModelSerializer 提供了默认的实现,如创建(create)和更新(update)方法,这使得在处理数据库操作时更为便捷。

优点
  • 自动字段映射:自动根据模型生成序列化字段。
  • 内置的创建和更新方法:默认实现了创建和更新数据库记录的方法。
  • 简化代码:减少了大量的样板代码,特别是在序列化字段与模型字段一一对应的情况下。

serializers.Serializer

Serializer 类是 DRF 中最基础的序列化器类,提供了更高的灵活性和控制。它不会自动根据模型生成字段,所有的字段都需要手动定义。你需要手动实现创建和更新的方法,这使得它在处理非标准的数据结构时更为适用。

优点
  • 高度灵活:可以用于序列化非 Django 模型的数据结构。
  • 完全控制:对序列化和反序列化过程有完全的控制权。
  • 广泛适用:适用于那些不直接与数据库模型对应的数据处理场景。

应用场景对比

  • 当你在处理直接映射到数据库模型的数据时,ModelSerializer 是一个更好的选择,因为它简化了很多工作。
  • 当你需要处理复杂的数据结构,或者数据来源不是 Django 模型时,使用 Serializer 可以给你更多的自由度。

示例转换

你提到的 RegisterSerializer 示例使用 ModelSerializer,包含了一个额外的非模型字段 confirm_password。如果你将其改为使用 Serializer,则需要手动实现数据的验证、保存逻辑,并且所有字段都需要明确声明。

from rest_framework import serializers

class RegisterSerializer(serializers.Serializer):
    username = serializers.CharField(max_length=32)
    password = serializers.CharField(max_length=64)
    confirm_password = serializers.CharField()

    def validate_password(self, value):
        print("密码:", value)
        return value

    def validate_confirm_password(self, value):
        print("重复密码:", value)
        print(self.initial_data)
        return value
    
    def create(self, validated_data):
        # 添加创建用户的逻辑
        user = User.objects.create_user(
            username=validated_data['username'],
            password=validated_data['password']
        )
        return user

    def update(self, instance, validated_data):
        # 添加更新用户的逻辑,如果适用
        pass

在这个例子中,所有字段都需要明确声明,并且你需要手动处理创建和更新逻辑,提供了更大的灵活性,但同时也增加了代码的复杂性。

posted on 2025-07-23 12:50  怡宝味汽水  阅读(20)  评论(0)    收藏  举报