django转换器
1.django转换器:django 2.x以后,为了取代 re_path
str:匹配除了路径分隔符(/)之外的非空字符串,这是默认的形式
int:匹配正整数,包含0。
slug:匹配字母、数字以及横杠、下划线组成的字符串。
uuid:匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00。
path:匹配任何非空字符串,包含了路径分隔符(/)
ps:path('books/<str:name>') ---->/books/1----》name=1---》当参数传入视图类的方法中
配置文件作用
概要
1.djagno项目要运行,优先执行配置文件的内容,做一下配置加载工作
-os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django项目名.settings')
2.任何一个django项目都有两套配置:
一套是项目自己的,自己有那个配置参数,优先用自己的
一套是内置的(django内置的)--->from django import settings
配置参数的作用
1.项目的根路径
BASE_DIR = Path(__file__).resolve().parent.parent
2.密钥
djagno中涉及到加密的,大部分都会用这个密钥
SECRET_KEY = 'django-insecure-eh=o(kt_70%8wj4r+le-7*$7t+fn%_2rfh61f09(2^&3q-5vk)'
3.调试模式DEBUG
DEBUG = False # 是否开启调试模式
ps:1.上线一定关闭
2.只要是调试模式:访问的路径不存在,他会显示出所有能访问的路径,视图类出了异常,浏览器中能看到
4.ALLOWED_HOSTS
项目是要部署在某个服务器上,这个列表写,部署服务器的ip地址, * 表示任意地址都可以
ALLOWED_HOSTS = ['*']
5.INSTALLED_APPS
里面有内置的app和我们自己写的app
INSTALLED_APPS = [
'django.contrib.admin', # 后台管理--->很多表不是它的,是别的app的
'django.contrib.auth', # auth 模块,UsrInfo表---->有6个表
'django.contrib.contenttypes', # 有个django_content_type表是这个app的
'django.contrib.sessions', # session相关的
'django.contrib.messages', # 消息框架
'django.contrib.staticfiles', # 静态文件开启的app
'app01.apps.App01Config', # app01
'rest_framework' # drf
]
ps:想看字符串里面的内容:
eg:'django.contrib.auth'
from django.contrib import auth
6.中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', # session相关
'django.middleware.common.CommonMiddleware', # 公共
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
8.模版所在路径
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'], # 必须是个列表
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
9.WSGI_APPLICATION项目上线
运行application
WSGI_APPLICATION = 'drf_day07.wsgi.application'
10.数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
11.密码认证相关
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
12.做国际化
LANGUAGE_CODE = 'zh-hans' --->语言
TIME_ZONE = 'Asia/Shanghai' --->时区
USE_I18N = True
USE_L10N = True
USE_TZ = True
"""
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
"""
13.静态文件
STATIC_URL = '/static/'
14.DEFAULT_AUTO_FIELD
表中,默认可以不写id,id主键自增,之前全是AutoField,长度很短
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
登陆功能
models.py
from django.db import models
# Create your models here.
class UserInfo(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
class UserToken(models.Model):
token = models.CharField(max_length=32)
user = models.OneToOneField(to=UserInfo,on_delete=models.CASCADE)
views.py
from .models import UserInfo,UserToken
from rest_framework.response import Response
import uuid
from rest_framework.viewsets import ViewSet
class UserView(ViewSet):
def login(self,request):
username = request.data.get('name')
password =request.data.get('pwd')
print(request.data)
print(username,password)
user_obj = UserInfo.objects.filter(username=username,password=password).first()
if not user_obj:
return Response({'code':101,'msg':'用户名或密码错误'})
else:
# 有这个用户,就应该返回加密字符串,并且写到UserToken中
# 用户在次登陆会更新UserToken中,该用户的token值,第一次登陆就会创建--->判断
uuid_str = uuid.uuid4()
# print(uuid_str,type(uuid_str)) # ffebb2ba-7048-475f-914e-3eda1ae07eee <class 'uuid.UUID'>
# 方式一
# if UserToken.objects.filter(user=user_obj).first():
# # 有这个用户更新token值
# UserToken.objects.filter(user=user_obj).update(token=str(uuid_str))
# else:
# UserToken.objects.create(token=str(uuid_str), user=user_obj)
# 方式二
UserToken.objects.update_or_create(user_id = user_obj.id,defaults={'token':str(uuid_str)})
return Response({"code":100,'msg':'登陆成功','token':uuid_str})
ps:update_or_create(self, defaults=None, **kwargs):
"""
def update_or_create(self, defaults=None, **kwargs):
'''
Look up an object with the given kwargs, updating one with defaults
if it exists, otherwise create a new one.
Return a tuple (object, created), where created is a boolean
specifying whether an object was created.
'''
"""
urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/',views.UserView.as_view({'post':'login'}) ),
]
认证组件
简介
1.APIView执行流程
1.在视图视图类的方法之前,执行了三大认证
2.顺序:认证-->权限-->频率
2.认证:如登录认证
登录认证--->控制,某个接口必须登录后才能访问
案例
需求:让查询所有接口,必须登录后才能访问
auth.py
from rest_framework.authentication import BaseAuthentication
from .models import UserToken
from rest_framework.exceptions import AuthenticationFailed
class LoginAuth(BaseAuthentication):
def authenticate(self, request): # 父类中有,一定要重写
"""
校验用户是否登陆-->请求中携带token就登陆了
token携带的地方-->是接口规定的-->可以是在请求地址中,也可以是在请求头中
"""
print(request.query_params)
token = request.query_params.get('token')
# 拿着token去UserToken表中去找
token_obj =UserToken.objects.filter(token=token).first()
if token_obj:
user= token_obj.user # 当前登录用户就是user
return user,token
else:
raise AuthenticationFailed('请登陆')
views.py
# 如何算登陆-->登录成功后,返回给前端一个token随机字符串,只要携带我给的随机字符串,我就能定位到是谁,就是这个人登录了
from .auth import LoginAuth
from rest_framework.views import APIView
from rest_framework.response import Response
class BookView(APIView):
authentication_classes = [LoginAuth]
def get(self,request):
return Response({'code':100,'msg':'查到了好多的书集信息'})
urls.py
urlpatterns = [
path('admin/', admin.site.urls),
path('login/',views.UserView.as_view({'post':'login'}) ),
path('books/', views.BookView.as_view()),
]
ps:访问:http://127.0.0.1:8000/books/?token=2c3cacb4-30f4-4760-962f-42a73c544b50
认证组件使用步骤(固定用法)
1.写一个类
1.这个类继承BaseAuthentication
2.在类中写:authenticate方法authenticate
3.在方法中,完成登陆认证,没有通过抛异常,通过就返回(user, token)-->登陆用户和tiken
2.1在视图类中,使用认证类(局部使用)
class BookView(APIView):
authentication_classes = [LoginAuth, ]
2.2 全局使用:--->必须局部禁用
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'app01.auth.LoginAuth'
],
}
ps: 1.不要在配置文件中,导入莫名其妙的包
2.全局使用后,局部禁用
class UserView(ViewSet):
authentication_classes = []
3.认证类的使用顺序
1.优先用视图类配置的
2.其次用项目配置文件
3.最后用drf默认的配置
ps:一旦通过认证,在request中就有当前登录用户-->request.user
def get(self, request):
# 一旦通过认证,在request中就有当前登录用户
print(request.user.name,'访问了接口')
权限组件
分析
1.登陆认证通过后,但有的功能(接口),只有超级管理员能做,有的功能所有登录用户都能做---->这就涉及到权限的设计了
2.权限设计:比较复杂--->有acl,rbac,abac
案例
需求:查询所有图书:所有登录用户都能访问(普通用户和超级管理员);删除图书,只有超级管理员能访问
permission.py
from rest_framework.permissions import BasePermission
class AdminPermission(BasePermission):
def has_permission(self, request, view):
"""
如果有权限,就返回True,没有权限,就返回False
判断user_type是不是1,根据当前用户-->request.user
"""
print(request.user,type(request.user))
if request.user.user_type == 1:
return True
else:
# 错误信息
self.message = '你好:%s,你没有权限'%request.user.username
return False
views.py
from .permission import AdminPermission
class BookDetailView(APIView):
permission_classes = [AdminPermission]
def delete(self,request,**kwargs):
return Response({'code':100,'msg':'删除成功'})
urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/',views.UserView.as_view({'post':'login'}) ),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
访问:http://127.0.0.1:8000/books/1/?token=2c3cacb4-30f4-4760-962f-42a73c544b50
权限类的使用步骤
1.写一个类,
1.继承BasePermission
2.在类中写方法:has_permission
1.如果有权限,就返回True
2.如果没有权限,就返回False
3.错误信息是self.message='字符串'
2.1 局部使用
class BookDetailView(APIView):
permission_classes = [AdminPermission, ]
2.2 全局使用
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'app01.permission.AdminPermission',
],
}
3.局部禁用
class BookView(APIView):
permission_classes = []
频率组件
分析
1.频率组件:限制访问频次
1.比如某个接口,一分钟只能访问5次,超过了就得等
2.限制方式
1.按IP地址限制
2.按用户id限制
案例
需求:同一ip不能够在一分钟以内访问三次以上
throttling.py
from rest_framework.throttling import SimpleRateThrottle
class MyThrottle(SimpleRateThrottle):
scope = 'nana'
def get_cache_key(self, request, view):
# 返回客户端ip地址
print(request.META)
ip = request.META.get('REMOTE_ADDR')
print('客户端的ip是:',ip)
return ip
项目.settings.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'nana':'3/m'
},
}
views.py
from .auth import LoginAuth
from rest_framework.views import APIView
from rest_framework.response import Response
from .throttling import MyThrottle
class BookView(APIView):
authentication_classes = [LoginAuth]
permission_classes = []
throttle_classes = [MyThrottle]
urls.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('login/',views.UserView.as_view({'post':'login'}) ),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookDetailView.as_view()),
]
频率类的使用步骤
1.写个类
1.继承:SimpleRateThrottle
2.重写某个方法:get_cache_key
1.可以返回ip或用户id
ps:ip:request.META.get('REMOTE_ADDR')
2.返回什么,就以什么做频率限制
3.写一个类属性,随意命名一个名
scope = 'nana'
4.在配置文件中配置:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'nana': '3/m' # 一分钟访问3次--->前面的key值是scope的值
},
}
4.全局用
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'nana':'3/m'
},
'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.MyThrottle'],
}
5.局部用
class BookView(APIView):
throttle_classes = [MyThrottle]
作业
0 认证类的token从请求头中取
1 登录接口,编写图书的5个接口
-不登录就能查询所有图书
-查询单条,新增,修改,删除,都需要登录后才访问
-删除和修改要超级管理员才能操作
-所有接口,一秒钟只能访问2次
-----一般人写不出来----
2 使用django中间件实现,按ip地址,一分钟只能访问5次的限制
认证类的token从请求头中取
authentication.py
from rest_framework.authentication import BaseAuthentication
from app01 import models
from rest_framework.exceptions import AuthenticationFailed
class LoginAuthentiction(BaseAuthentication):
def authenticate(self, request):
# 获取token值--->token值在请求头中
print(request.META)
token = request.META.get('HTTP_TOKEN')
# print(token)
# 根据token在usertoken表中查找
token_obj = models.UserToken.objects.filter(token=token).first()
print(token_obj)
# 如果有token,返回token user,没有抛异常
if token_obj:
user = token_obj.user
return token,user
else:
raise AuthenticationFailed('请登陆哦')
views.py
rom rest_framework.views import APIView
from app01 import models
from rest_framework.response import Response
from .authentication import LoginAuthentiction
class BookView(APIView):
authentication_classes = [LoginAuthentiction]
def get(self,request):
# print(request.user)
return Response({'code':100,'msg':'查询了很多数据'})
注意
1.在Django中处理具体请求的时候,使用request.META.get(key)方法去获取header中key对应的value值,得注意的是官方文档里面有说明 Django获取自定义header信息的方法:
1.所有header名大写,将连接符“-”改为下划线“_”
2.除了 CONTENT_LENGTH 和 CONTENT_TYPE,其他的头部在META字典中的key值都会被加上“HTTP_”的前缀
登录接口,编写图书的5个接口
1.不登录就能查询所有图书
2.查询单条,新增,修改,删除,都需要登录后才访问
3.删除和修改要超级管理员才能操作
4.所有接口,一秒钟只能访问2次