Django REST framework中部分机制是如何实现的?

本文深入探讨Django REST Framework(DRF)的八大核心组件:认证、权限、限流、解析器、序列化、渲染器、验证及其实现原理,帮助读者全面理解DRF的工作机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. DRF是如何实现authentication的?

  • authentication(认证):所谓认证就是身份的认证,是否登陆,确定你是谁。

Authentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with. The permission and throttling policies can then use those credentials to determine if the request should be permitted.

就简单的authentication而言,是验证用户名和密码是否都能匹配上。如果是SessionAuthentication,TokenAuthentication则是分别增加了csrf的验证,token的验证。

不要忘记,身份验证本身不会允许或不允许request,它仅会标识发出request的凭据,也就是返回request.user和request.auth。

如果认证通过,返回值写入request.userrequest.auth中。

2. DRF是如何实现permisson验证的?

  • permission(权限):确定你可以访问哪些接口。
    DRF利用authentication后返回的request.userrequest.auth数据进行权限验证。
    在DRF中有两种permission,分别是view level permissionobject level permission。处于性能原因,并没有对所有的请求做object level permission。
# rest_framework/permissions.py
class BasePermission(metaclass=BasePermissionMetaclass):
    """
    A base class from which all permission classes should inherit.
    """

    def has_permission(self, request, view):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return True

    def has_object_permission(self, request, view, obj):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return True


class IsAuthenticated(BasePermission):
    """
    Allows access only to authenticated users.
    """

    def has_permission(self, request, view):
        return bool(request.user and request.user.is_authenticated)

每一个Permission类都是一种权限的配置模式,需要重写has_permission或者has_object_permission方法来决定如何决定request是否具有permission

3. DRF是如何实现throtting的?

  • throttling(限流):限制访问接口的频率等。

throttlingpermission类似,它决定是否应授权request。 限流用于控制客户端可以向API发出的request的速率(一段时间内只能请求多少次),或者带宽等。

机制是:
Throttle 中有一个self.history (一个dict,规定时间间隔内客户端的访问时间戳的列表),key为客户端ip,value为客户端请求的timestamp的列表,这样就能限制客户端在规定时间间隔内的请求频率了。如果有爬虫来频繁的访问你的API,这样就可以限制其访问次数,降低服务器的压力。

4. DRF是如何实现parser的?

parser:解析器。

在DRF中,parser的作用是将前端传过来的数据转换成python数据格式。根据request header中的 Content-Type决定使用什么parser来解析数据。

JSONParser为例:

# rest_framework/parsers.py

class JSONParser(BaseParser):
    """
    Parses JSON-serialized data.
    """
    media_type = 'application/json'
    renderer_class = renderers.JSONRenderer
    strict = api_settings.STRICT_JSON

    def parse(self, stream, media_type=None, parser_context=None):
        """
        Parses the incoming bytestream as JSON and returns the resulting data.
        """
        parser_context = parser_context or {}
        encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET)

        try:
            decoded_stream = codecs.getreader(encoding)(stream)
            parse_constant = json.strict_constant if self.strict else None
            return json.load(decoded_stream, parse_constant=parse_constant)
        except ValueError as exc:
            raise ParseError('JSON parse error - %s' % str(exc))

5. DRF是如何实现serialization的?

Django REST Framework中通过serializer对客户端传递过来的数据进行 反序列化 ,或者对查询的出来的 model 对象进行序列化

  • serializing:将对象 -> python数据格式(如:dict)
  • deserializing:将python数据格式 -> 对象
# models.py
from datetime import datetime

class Comment(object):
    def __init__(self, email, content, created=None):
        self.email = email
        self.content = content
        self.created = created or datetime.now()

comment = Comment(email='leila@example.com', content='foo bar')
# serializers.py
from rest_framework import serializers

class CommentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()
# python3 manage.py shell_plus
serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}

from rest_framework.renderers import JSONRenderer

json = JSONRenderer().render(serializer.data)
json
# b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'

上面的例子中,通过CommentSerializer实例将comment这个model实例实例对象进行序列化序列化的结果是一个dict。然后通过JSONRenderer中的render()实例方法将这个序列化后的数据转换成json数据格式,最终传递给客户端。

前端传入数据创建一个model或是修改model的过程如下图所示:

graph TD

前端数据 --> Router
Router --> View 或 ViewSet
view --> parser
parser --> serializer.is_valid方法验证数据
serializer.is_valid方法验证数据 --> serilaizer.save方法
serilaizer.save方法 --> Model.objects.create方法
 Model.objects.create方法--> 将对model实例对象的更改应用到db中

6. DRF是如何实现renderer的?

renderer:渲染器

renderer用于将serialize(序列化)后的response转换为特定的媒体类型,这个媒体类型通常为客户端发起请求时请求头中的Accept的值所决定的。

JSONRenderer为例:

# rest_framework/renderers.py
class JSONRenderer(BaseRenderer):
	def render(self, data, accepted_media_type=None, renderer_context=None):
        """
        Render `data` into JSON, returning a bytestring.
        """
        if data is None:
            return b''

        renderer_context = renderer_context or {}
        indent = self.get_indent(accepted_media_type, renderer_context)

        if indent is None:
            separators = SHORT_SEPARATORS if self.compact else LONG_SEPARATORS
        else:
            separators = INDENT_SEPARATORS

        ret = json.dumps(
            data, cls=self.encoder_class,
            indent=indent, ensure_ascii=self.ensure_ascii,
            allow_nan=not self.strict, separators=separators
        )

        # We always fully escape \u2028 and \u2029 to ensure we output JSON
        # that is a strict javascript subset.
        # See: http://timelessrepo.com/json-isnt-a-javascript-subset
        ret = ret.replace('\u2028', '\\u2028').replace('\u2029', '\\u2029')
        return ret.encode()

实际就是通过json.dumps()将python数据格式转换成了json格式。

7. DRF是如何实现validation的?

validation也就是验证。

DRF对前端传递过来的数据需要验证之后才能应用到model上。而验证是针对这些需要验证的field而言的。以EmailField字段为例:

# rest_framework/fields.py

# EmailField 中的validator是 EmailValidator,当前端传递过来的数据需要验证时候,调用EmailValidator的实例对象进行验证
class EmailField(CharField):
    default_error_messages = {
        'invalid': _('Enter a valid email address.')
    }

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        validator = EmailValidator(message=self.error_messages['invalid'])
        self.validators.append(validator)

看看Django中的EmailValidator

# django/core/validators.py

@deconstructible
class EmailValidator:
	......此处省略若干代码......
	def __call__(self, value):
        if not value or '@' not in value:
            raise ValidationError(self.message, code=self.code)

        user_part, domain_part = value.rsplit('@', 1)

        if not self.user_regex.match(user_part):
            raise ValidationError(self.message, code=self.code)

        if (domain_part not in self.domain_whitelist and
                not self.validate_domain_part(domain_part)):
            # Try for possible IDN domain-part
            try:
                domain_part = punycode(domain_part)
            except UnicodeError:
                pass
            else:
                if self.validate_domain_part(domain_part):
                    return
            raise ValidationError(self.message, code=self.code)

8. 参考文献

[1] Django REST Framework官方文档

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值