GVKun编程网logo

Django rest-framework框架-content-type(django rest framework框架中都有哪些组件)

16

本文将分享Djangorest-framework框架-content-type的详细内容,并且还将对djangorestframework框架中都有哪些组件进行详尽解释,此外,我们还将为大家带来关于

本文将分享Django rest-framework框架-content-type的详细内容,并且还将对django rest framework框架中都有哪些组件进行详尽解释,此外,我们还将为大家带来关于$Django cbv源码分析 djangorestframework框架之APIView源码分析、django rest framework authentication、Django REST Framework 批量更新 rest_framework_extensions、Django rest framework 框架的相关知识,希望对你有所帮助。

本文目录一览:

Django rest-framework框架-content-type(django rest framework框架中都有哪些组件)

Django rest-framework框架-content-type(django rest framework框架中都有哪些组件)

表结构讨论:

是用一张表价格策略表来记录两种不同的价格策略

 

content-type原理:

 

使用一张表来记录不同课程的价目,增加一行表名称

注释: 适用于多张表关联一张表的情况

 

 

 会自动生成这种的结构:

content_type: Django内置的一个组件, 帮助开发者做连表操作
              连表操作: 普通的又 ForeignKey,OneToOne, ManyToMany
              高级连表操作: content_type


第一版: 普通方式来生成这种表关联
class Course(models.Model):
	"""普通课"""
	title = models.CharField(max_length=32)

class DegreeCourse(models.Model):
	"""学位课"""
	title = models.CharField(max_length=32)

class PricePolicy(models.Model):
	"""价格策略"""
	price = models.IntegerField()
	period = models.IntegerField()

	table_name = models.CharField(verbose_name="关联的表名称")
	object_id = models.CharField(verbose_name="关联的表中的数据行ID")

第二版: 利用contentype来做多表关联
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.contrib.contenttypes.models import ContentType
class Course(models.Model):
	"""普通课"""
	title = models.CharField(max_length=32)
	# 用于反向查找
	price_policy_list = GenericRelation("PricePolicy")

class DegreeCourse(models.Model):
	"""学位课"""
	title = models.CharField(max_length=32)
	# 用于反向查找
	price_policy_list = GenericRelation("PricePolicy")

class PricePolicy(models.Model):
	"""价格策略"""
	price = models.IntegerField()
	period = models.IntegerField()
    #关联到ContentType表 
	table_name = models.ForeignKey(ContentType, verbose_name="关联普通课表或者学位课表")
	object_id = models.IntegerField(verbose_name="关联普通课表或者学位课表中的数据行ID")

	#1. 为学位课PYTHON全栈 添加一个价格策略 一个月 9.9
	#obj = DegreeCourse.objects.filter(title="PYTHON全栈").first()
	#obj.id
	#cobj = ContentType.objects.filter(model = ''course'').first()
	#cobj.id
	#PricePolicy.objects.create(price=''9.9'',period=''30'',content_type_id=cobj.id,object_id=obj.id)
	#以上操作用下面代替
	content_object = GenericForeignKey(''content_type'', ''object_id'')

# 添加view例子

def test(request):
	#1. 为学位课PYTHON全栈 添加一个价格策略 一个月 9.9
	obj1 = DegreeCourse.objects.filter(title="PYTHON全栈").first()
	PricePolicy.objects.create(price=9.9,period=''一个月'',content_type=obj1)

	obj2 = DegreeCourse.objects.filter(title="PYTHON全栈").first()
	PricePolicy.objects.create(price=39.9,period=''二个月'',content_type=obj2)

	obj3 = DegreeCourse.objects.filter(title="PYTHON全栈").first()
	PricePolicy.objects.create(price=59.9,period=''三个月'',content_type=obj3)

	#2. 根据课程ID获取课程, 并获取该课程的所有价格策略
	course = models.Course.objects.filter(id=1).first()
	price_policys = course.price_policy_list.all()

	return HttpResponse("添加成功")

  

 

$Django cbv源码分析 djangorestframework框架之APIView源码分析

$Django cbv源码分析 djangorestframework框架之APIView源码分析

1 CBV的源码分析

#视图
class login (View):
    pass
#路由
url(r''^books/$'', views.login.as_view())
#阅读源码:
#左侧工程栏--->设置图标-->点击--->show members(能看到py文件,pu下的类,类下的方法)
-Class Base View(基于类的视图)
    -Function Base View(基于函数的视图)
    -def as_view 类方法 :返回view
    -def view:as_view的内的函数(闭包)
-python中一切皆对象:函数也是对象 -hasattr(self, ''get'')--判断self类中是不是有该(get)方法 -setattr(self,get,get_all):相当于把get函数,变成了get_all -getattr(self, ''get''):拿到get函数的内存地址 - def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, ''get'') and not hasattr(self, ''head''): self.head = self.get self.request = request self.args = args self.kwargs = kwargs #执行:dispatch:谁的dispatch方法?写的cbv的那个c,视图中的那个视图类 #我这个类如果没有写dispatch,会执行View中的dispatch方法 return self.dispatch(request, *args, **kwargs) -def dispatch(self, request, *args, **kwargs): #request.method 前台请求的方法,转成了小写 #http_method_names View中定义的一个列表:是一堆请求方式 if request.method.lower() in self.http_method_names: #getattr的第三个参数是默认值:self.http_method_not_allowed #拿到get方法的内存地址 handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed #get(request,*args, **kwargs) return handler(request, *args, **kwargs

 总结:*******请求来了--->as_view---->view---->dispatch--->分发到不同的函数,执#行函数,拿到结果

 2 djangorestframework框架

   安装:djangorestframework
   -它是一个app,要在咱的项目中用
   -只是快速的构建resful规范的接口
   -csrf_exempt:局部禁用csrf(csrf是可以局部使用,局部禁用)
   -以后再执行的dispatch方法是APIView的dispatch方法
   -getattr和setattr
   重点掌握这三点:
    -request.data 是个方法,包装成了属性,前台传过来body体中数据的数据,放在里面
    -request.query_params  这个是原来GET中的数据
    -request把原来的request包装进去了

3  APIView源码分析

 @classmethod
    def as_view(cls, **initkwargs):
        """
        Store the original class on the view function.

        This allows us to discover information about the view when we do URL
        reverse lookups.  Used for breadcrumb generation.
        """
        if isinstance(getattr(cls, ''queryset'', None), models.query.QuerySet):
            def force_evaluation():
                raise RuntimeError(
                    ''Do not evaluate the `.queryset` attribute directly, ''
                    ''as the result will be cached and reused between requests. ''
                    ''Use `.all()` or call `.get_queryset()` instead.''
                )
            cls.queryset._fetch_all = force_evaluation

        view = super(APIView, cls).as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs

        # Note: session based authentication is explicitly CSRF validated,
        # all other authentication is CSRF exempt.
        return csrf_exempt(view)
as_view方法
def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django''s regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
dispatch
def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
        parser_context = self.get_parser_context(request)

        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
initialize_request
def initial(self, request, *args, **kwargs):
        """
        Runs anything that needs to occur prior to calling the method handler.
        """
        self.format_kwarg = self.get_format_suffix(**kwargs)

        # Perform content negotiation and store the accepted info on the request
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg

        # Determine the API version, if versioning is in use.
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        # Ensure that the incoming request is permitted
        self.perform_authentication(request)
        self.check_permissions(request)
        self.check_throttles(request)
initial方法(内部调用认证,权限,频率)

 总结:*******请求来了--->as_view---->view---->dispatch(apiview的比上面的多做了  包了个request对象生成新的request对象  和调用initial方法 都是apiview自己的方法)--->分发到不同的函数,执#行函数,拿到结果

django rest framework authentication

django rest framework authentication

身份验证


身份验证是将传入请求与一组识别凭证(例如请求的用户或其签名的令牌)相关联的机制。然后,权限和限制策略可以使用这些凭据来确定请求是否应该被允许。

REST framework 提供了许多开箱即用的身份验证方案,同时也允许你实施自定义方案。

身份验证始终在视图的开始处运行,在执行权限和限制检查之前,在允许继续执行任何其他代码之前。

request.user 属性通常会设置为 contrib.auth 包的 User 类的一个实例。

request.auth 属性用于其他身份验证信息,例如,它可以用来表示请求已签名的身份验证令牌。

如何确定身份验证


认证方案总是被定义为一个类的列表。 REST framework 将尝试使用列表中的每个类进行认证,并将使用成功认证的第一个类的返回值来设置 request.user 和 request.auth 。

如果没有类进行身份验证,则将 request.user 设置为 django.contrib.auth.models.AnonymousUser 的实例,并将 request.auth 设置为 None.

可以使用 UNAUTHENTICATED_USER 和 UNAUTHENTICATED_TOKEN 设置修改未经身份验证的请求的 request.user 和 request.auth 的值。

设置认证方案


默认的认证方案可以使用 DEFAULT_AUTHENTICATION_CLASSES setting 全局设置。例如

REST_FRAMEWORK = {
    ''DEFAULT_AUTHENTICATION_CLASSES'': (
        ''rest_framework.authentication.BasicAuthentication'',
        ''rest_framework.authentication.SessionAuthentication'',
    )
}

基于 APIView 类的视图上设置身份验证策略

authentication_classes = (SessionAuthentication,)

API参考

BasicAuthentication

该认证方案使用 HTTP Basic Authentication,并根据用户的用户名和密码进行签名。Basic Authentication 通常只适用于测试。

如果成功通过身份验证,BasicAuthentication 将提供以下凭据。

request.user 是一个 Django User 实力.

request.auth 是 None.

未经身份验证的响应被拒绝将导致 HTTP 401 Unauthorized 的响应和相应的 WWW-Authenticate header。

SessionAuthentication

此认证方案使用 Django 的默认 session 后端进行认证。Session 身份验证适用于与您的网站在同一会话环境中运行的 AJAX 客户端。

如果成功通过身份验证,则 SessionAuthentication 会提供以下凭据。

request.user 是一个 Django User 实例. request.auth 是 None. 未经身份验证的响应被拒绝将导致 HTTP 403 Forbidden 响应。

如果您在 SessionAuthentication 中使用 AJAX 风格的 API,则需要确保为任何 “不安全” 的 HTTP 方法调用(例如 PUT,PATCH,POST 或 DELETE 请求)包含有效的 CSRF 令牌。

JSONWebTokenAuthentication

详见jwt篇

Django REST Framework 批量更新 rest_framework_extensions

Django REST Framework 批量更新 rest_framework_extensions

Django REST framework 是一套基于 Django 框架编写 RESTful 风格 API 的组件。

 其中 mixins 配合 viewsets 能极其方便简化对数据的增删改查,

但本身并没有对数据的批量更新删除,利用 rest_framework_extensions 扩展包可以轻松帮我们实现这些功能。

安装使用

pip install rest_framework_extensions

 

views.py

在视图类中继承 ListUpdateModelMixin

1 from rest_framework_extensions.mixins import ListUpdateModelMixin
2 class ShoppingCartViewSet(ListUpdateModelMixin, viewsets.ModelViewSet):
3     pass

 

settings.py

1 CORS_ALLOW_HEADERS = [''*'']  # 允许的请求头
2 CORS_ORIGIN_ALLOW_ALL = True  # 允许跨域
3 
4 REST_FRAMEWORK_EXTENSIONS = {
5     ''DEFAULT_BULK_OPERATION_HEADER_NAME'': None
6 }

使用浏览器本地测试,在请求头加上:X-BULK-OPERATION: true

使用 patch 方式请求测试成功,状态码 204,不会返回任何东西

 

使用 PUT 方法批量更新

以上在浏览器使用正常,但发现在微信小程序中并不支持 patch 方法,只能用 put 方法。要么重新再写一个 put 接口,要么更改源码。

ctrl 点击查看 ListUpdateModelMixin 码源,果真只有 put 方法。怎么办?

把 patch 方法复制粘贴一份,改名为 put 即可,同样测试成功。

\Lib\site-packages\rest_framework_extensions\bulk_operations\mixins.py

 

对于以上修改。对于没有使用虚拟环境的同学,个人建议不要直接修改源码,一定要把整个包拷到项目目录下再修改。

在项目目录下新建 extra_apps 文件夹,用来存放要修改的第三方包。

再在 settings.py 中添加以下。优先从 extra_apps 文件夹导包。

import os
import sys
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(BASE_DIR, ''extra_apps''))

 微信小程序测试正常

 

 

 

 

Django rest framework 框架

Django rest framework 框架

一、十个方面

  权限  认证  访问频率限制 序列化 路由 视图 分页  解释器 渲染器 版本

二、Django REST framework 框架介绍

  用于构建 Web API,官方网站:https://www.django-rest-framework.org/

三、安装

  pip install djangorestframework

  pip install markdown #支持可浏览的 API

  pip install django-filter # 过滤支持

四、设置 setting.py 文件  

#将项目添加到APP中
INSTALLED_APPS = [ ... ''rest_framework'', ]
#添加中间件
REST_FRAMEWORK = { # Use Django''s standard `django.contrib.auth` permissions, # or allow read-only access for unauthenticated users. ''DEFAULT_PERMISSION_CLASSES'': [ ''rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly'' ] }

五、用户登录API+验证

  1. 创建用户表和用户登录验证的 token

#models.py文件
class UserInfo(models.Model):
    user_type_choices=(
        (1,''普通用户''),
        (2, ''VIP''),
        (3, ''SVIP''),
    )
    id = models.AutoField(primary_key=True)
    user_type = models.IntegerField(choices=user_type_choices,verbose_name=''用户等级'')
    username = models.CharField(max_length=32,unique=True,verbose_name=''用户名'')
    password = models.CharField(max_length=64,verbose_name=''用户密码'')

class UserToken(models.Model):
    user = models.OneToOneField(to=''UserInfo'')
    token = models.CharField(max_length=64,verbose_name=''用户的token'')

  2. 创建用户 Token 的 md5 算法  

#当前算法使用的hashlib的md5算法加上时间
import hashlib
import time
def md5(user):
    ctime = str(time.time())
    m = hashlib.md5(bytes(user,encoding=''utf-8''))
    m.update(bytes(ctime,encoding=''utf-8''))
    return m.hexdigets()

  3. 根据用户名创建 Token

from rest_framework.views import APIView
class AuthView(APIView):
    def post(self, request, *args, **kwargs):
        ret = {''code'': 1000, ''msg'': None}
        try:
            # 获取用户名
            user = request._request.POST.get(''username'')
            # 获取密码
            pwd = request._request.POST.get(''password'')
            # 核对数据的正确性
            obj = models.UserInfo.object.filter(username=user, password=pwd).first()
            if not obj:
                ret[''code''] = 1001
                ret[''msg''] = ''用户名或密码错误''
            # 为登录用户创造token
            token = md5(user)
            # 存在就更新,不存在就创新
            models.UserToken.object.update_or_create(user=obj, defaults={''token'': token})
            ret[''token''] = token
        except Exception as e:
            ret[''code''] = 1002
            ret[''msg''] = ''请求异常''
        return JsonResponse(ret)

   4. 验证用户传递的 Token 是否正确,来验证登录用户是否正确

class Authtication(BasicAuthentication):
    def authenticate(self, request):
        token = request._request.Get.get(''token'')
        token_obj = models.UserToken.object.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed(''用户验证失败'')
        return (token_obj.user,token_obj)
    
    def authenticate_header(self, request):
        pass

  5. 修改 settings.py 配置文件,加装全局变量配置

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES":[''函数所在路径.函数名,如:api.utils.auth.Authtication'']
}

  6. 在其他视图函数中引用配置文件,完成只有登录用户才可以访问的控制

  authentication_classess= []

六、匿名用户登录

  1. 修改 settings.py 配置文件,加装全局变量配置

REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": [''函数所在路径.函数名,如:api.utils.auth.Authtication''],
    "UNAUTHENTICATED_USER": None,
    "UNAUTHENTICATED_TOKEN": None
}

  2. 创建匿名用户的验证函数

class FirstAuthtication(BasicAuthentication):
    def authenticate(self, request):
        pass
    
    def authenticate_header(self, request):
        pass

七、按权限限定用户访问的页面

  1. 创建限制用户权限的函数

from rest_framework.permissions import BasePermission
class MyPermission(BasePermission):
   message = "只用3级用户才可以访问"
def has_permission(self, request, view): #只有3级用户才可以访问 if request.user.user_type !=3: return False else: return True

  2. 视图函数使用验证方法(推举使用该方法,而不是全局配置)

  permission_classess = [MyPermission,]

八、控制访问频率次数

  1. 创建访问频率次数的方法函数

import time
from rest_framework.throttling import BaseThrottle
VISIT_RECORD={}
class VisitThrottle(BaseThrottle):
    #60秒只能访问3次
    def __init__(self):
        self.history = None

    def allow_request(self, request, view):
        #获取用户的IP,根据IP进行控制
        ip = request.META.get("REMOTE_ADDR")
        ctime = time.time()
        if ip not in VISIT_RECORD:
            VISIT_RECORD[ip]=[ctime,]
            return True
        history = VISIT_RECORD.get(ip)
        self.history = history
        while history and history[-1] < ctime - 60:
            history.pop()
        if len(history) < 3:
            history.insert(0,ctime)
            return True

    def wait(self):
        ''''''
        需要等待多长时间再次访问
        :return:
        ''''''
        ctime = time.time()
        return  60 -(ctime-self.history[-1])

     2. 使用框架内部的控制策略

#修改配置文件信息,settings.py
REST_FRAMEWORK = {
    "DEFAULT_THROTTLE_RATES":{
        "IP":''3/m'',
        "UserName":''10/m''
    }
}
#设置控制策略函数
from rest_framework.throttling import SimpleRateThrottle
class VisitThrottle(SimpleRateThrottle):
    #根据IP的访问控制
    scope = "IP"
    def get_cache_key(self, request, view):
        return self.get_ident(request)

class UserThrottle(SimpleRateThrottle):
    #根据用户名的访问控制
    scope = "UserName"
    def get_cache_key(self, request, view):
        return request.user.username

九、版本控制策略

#修改配置文件信息
REST_FRAMEWORK = {
    #默认版本号
    "DEFAULT_VERSION":''v1'',
    #允许的版本号
    "ALLOWED_VERSIONS":[''v1'',''v2''],
    #版本的Key的值
    "VERSION_PARAM":''version''
}
#引用版本规则
from rest_framework.versioning import QueryParameterVersioning
class UserView():
    versioning_class = QueryParameterVersioning
    def get(self,request,*args,**kwargs):
        print(request.version)
        return

 十、解释器

from rest_framework.parsers import JSONParser,FormParser
#JSON解释器,POST解释器,
parser_classes = [JSONParser,FormParser]

请求头:

  • User-Agent:产生请求的浏览器类型。
  • Accept:客户端可识别的内容类型列表。
  • Host:请求的主机名,允许多个域名同处一个 IP 地址,即虚拟主机。

状态码:

  • 1xx:指示信息 -- 表示请求已接收,继续处理。
  • 2xx:成功 -- 表示请求已被成功接收、理解、接受。
  • 3xx:重定向 -- 要完成请求必须进行更进一步的操作。
  • 4xx:客户端错误 -- 请求有语法错误或请求无法实现。
  • 5xx:服务器端错误 -- 服务器未能实现合法的请求。

请求方法:

十一、序列化

  1. 基础用法

#序列化方法函数
from rest_framework import serializers
class UserINfoSerializer(serializers.Serializer):
    #带choise的序列化
    x1 = serializers.CharField(source="user_type")
    #直接获得choise的中文内容
    x2 = serializers.CharField(source="get_user_type_display")
    #正常的序列化
    username = serializers.CharField()
    #一对多
    gp = serializers.CharField(source="group.title")
    #多对多
    rls = serializers.SerializerMethodField()#自定义显示
    def get_rls(self,row):
        role_obj_list = row.roles.all()
        ret = []
        for item in role_obj_list:
            ret.append({"id":item.id,"title":item.title})
        return  ret

#引入序列化
class UserInfoView(APIview):
    def get(self,request,*args,**kwargs):
        user = models.UserInfo.object.all()
        ser = UserINfoSerializer(instance=user,many=True)
        ret = json.dumps(ser.data,ensure_ascii=False)
        return HttpResponse(ret)

  2. 使用自带的序列化方法

#序列化方法函数
from rest_framework import serializers
class UserINfoSerializer(serializers.ModelSerializer):    
    class Meta:
        model = models.UserInfo
        #获取所有的内容
        #fields = "__all__"
        #自定义获取的内容
        fields = [''id'',''username'']
        depth = 0 #获取到的层级 0-10
#使用序列化方法        
class UserInfoView(APIView):
    def get(self,request,*args,**kwargs):
        users = models.UserInfo.objcet.all()
        ser = UserINfoSerializer(instance=users,many=True,context={''request'':request})
        ret = json.dumps(ser.data,ensure_ascii=False)
        return HttpResponse(ret)

  3. 序列化验证

#验证方法
from rest_framework import serializers
class XXValidator(object):
    def __init__(self,base):
        self.base = base
        
    def __call__(self,value):
        if not value.startswith(self.base):
            message = ''XXX的%s错误'' % self.base
            raise serializers.ValidationError(message)
#引入验证方法       
class UserGroupSerializer(serializers.Serializer):
    title = serializers.CharField(error_messages={''required'':''XXX问题''},validators=[XXValidator(''内容''),])

十二、分页

from rest_framework.views import APIView
from rest_framework.pagination import PageNumberPagination
#自定义显示内容
class MypageNumberPagination(PageNumberPagination):
    page_size = 2 #每页显示的内容
    page_query_param = ''page''#key值
#只用自定义显示的内容    
class PagerView(APIView):
    def get(self,request,*args,**kwargs):
        #获取所有数据
        roles = models.Role.object.all()
        #创建分页对象
        pg = PageNumberPagination()
        #获取分页数据
        pager_roles = pg.MypageNumberPagination(queryset=roles,request=request,view=self)
        #对数据进行序列化,PagerSerialiser的方法,需要自定义
        ser = PagerSerialiser(instance=pager_roles,many=True)
        #返回基础数据
        #return Response(ser.data)
        #返回带上一页,下一页地址的数据
        return pg.get_paginated_response(ser.data)

 

关于Django rest-framework框架-content-typedjango rest framework框架中都有哪些组件的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于$Django cbv源码分析 djangorestframework框架之APIView源码分析、django rest framework authentication、Django REST Framework 批量更新 rest_framework_extensions、Django rest framework 框架等相关内容,可以在本站寻找。

本文标签: