新建项目REST02
init.py,安装驱动
(这里如果pymysql显红,可能是没有安装,安装:pip install pymysql)
配置django-rest-framework
(如果没有安装,先安装:pip install djangorestframework)
配置数据库
(django原本的可能是sqlite。这里我们改成mysql)
这里面包含了我自己的数据库账号密码,还有表名,记得修改
配置缓存
安装redis:pip install django_redis
安装好之后配置
CACHES = {
'default': {
'BACKEND': 'django_redis.cache.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
'OPTIONS': {
'CLIENT_CLASS': 'django_redis.client.DefaultClient',
},
'TIMEOUT': 60 * 60 * 2
}
}
配置好之后记得启动redis:redis-server.exe redis.windows.conf
(如果计算机里没有下载redis参考:https://blog.csdn.net/a__int__/article/details/103648033)
redis启动后这个cmd窗口不要关闭,关了redis就关闭了
登录
创建数据库(表名记得和setting里的表名一致)
迁移
python manage.py migrate
如果迁移过程出现问题参考:
https://blog.csdn.net/a__int__/article/details/103837018
注意,刚建的工程迁移出现问题一般是版本问题引起的
登陆时点测试如果出现问题,参考:
https://www.cnblogs.com/zzliu/p/10806854.html
https://www.cnblogs.com/jcxioo/p/11606044.html
python manage.py startapp App
用户和地址是一对多关系
App/models.py
from django.db import models
class User(models.Model):
u_name = models.CharField(max_length=16, unique=True)
u_password = models.CharField(max_length=256)
class Address(models.Model):
a_address = models.CharField(max_length=128)
a_user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
迁移
python manage.py makemigrations
python manage.py migrate
迁移出现问题参考: https://blog.csdn.net/a__int__/article/details/103837018
from App.models import User, Address
from rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'id', 'u_name', 'u_password')
class AddressSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Address
fields = ('url', 'id', 'a_address')
import uuid
from App.models import User
from App.serializers import UserSerializer
from django.core.cache import cache
from rest_framework import exceptions
from rest_framework.generics import CreateAPIView
from rest_framework.response import Response
class UserAPIView(CreateAPIView):
serializer_class = UserSerializer
queryset = User.objects.all()
def post(self, request, *args, **kwargs):
action = request.query_params.get('action')
if action == 'login':
u_name = request.data.get('u_name')
u_password = request.data.get('u_password')
try:
user = User.objects.get(u_name=u_name)
if user.u_password != u_password:
# AuthenticationFailed认证失败
raise exceptions.AuthenticationFailed
token = uuid.uuid4().hex
cache.set(token, user.id, timeout=60*60)
data = {
"msg": "登录成功",
"status": 200,
"token": token,
}
return Response(data)
except User.DoesNotExist:
raise exceptions.NotFound
if action == 'register':
return self.create(request, *args, **kwargs)
else:
raise exceptions.ParseError
创建路由App/urls.py
在根路由REST02/urls.py分配
运行
打开postman工具,对接口进行测试
注册一个用户
登录
path('address/', views.AddressAPIView.as_view(
{
'post': 'create',
}
)),
re_path('address/(?P\d+)/' , views.AddressAPIView.as_view(
{
'get': 'retrieve',
}), name='address-detail'),
新建认证类auth.py (认证只有登录的用户才能添加地址)
新建权限类permissions.py
from App.models import User
from rest_framework.permissions import BasePermission
class RequireLoginPermission(BasePermission):
def has_permission(self, request, view):
return isinstance(request.user, User)
# 注意,上面张截图的代码有写错,以下面代码为准
# 认证
authentication_classes = (LoginAuthentication,)
# 权限
permission_classes = (RequireLoginPermission,)
尝试访问
例:没有访问权限
例:登陆后,成功访问
查看数据库:数据成功入库(目前还没有级联用户)
# 重写create方法
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
# 地址级联用户
user = request.user
a_id = serializer.data.get('id')
address = Address.objects.get(pk=a_id)
address.a_user = user
address.save()
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
# list,该方法可以返回对象列表
# 这里我们重写list,使其返回的地址列表只能是当前登录用户的
def list(self, request, *args, **kwargs):
# 获取当前用户的地址
queryset = self.filter_queryset(self.queryset.filter(a_user=request.user))
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
测试:
先查看数据库里用户和地址表
登录用户qqq,获取地址列表
# 认证
authentication_classes = (LoginAuthentication,)
# 权限
permission_classes = (RequireLoginPermission,)
def retrieve(self, request, *args, **kwargs):
if kwargs.get('pk') != str(request.user.id):
# 如果当前请求的id不等于查询的id无法获取数据,返回认证失败
raise exceptions.AuthenticationFailed
instance = self.get_object()
serializer = self.get_serializer(instance)
return Response(serializer.data)
序列化器(注意:这里我把UserSerializer和AddressSerializer上下交换了位置)
# 这是目前序列化器里所有代码
from App.models import User, Address
from rest_framework import serializers
class AddressSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Address
fields = ('url', 'id', 'a_address')
class UserSerializer(serializers.HyperlinkedModelSerializer):
# 因为模型里address设置了外键user,所以address有一个隐性属性address_set
address_set = AddressSerializer(many=True,read_only=True)
class Meta:
model = User
fields = ('url', 'id', 'u_name', 'u_password', 'address_set')
from App.models import User
from rest_framework.throttling import SimpleRateThrottle
# 继承自rest_framework.throttling的SimpleRateThrottle
class UserRateThrottle(SimpleRateThrottle):
# 相当于这个节流的名字,可以添加到在setting配置里面
scope = 'user'
# 重写get_cache_key方法
def get_cache_key(self, request, view):
if isinstance(request.user, User):
ident = request.auth
else:
ident = self.get_ident(request)
return self.cache_format % {
'scope': self.scope,
'ident': ident
}
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': (
# from rest_framework.throttling import UserRateThrottle
# UserRateThrottle,
# 这里我们用自己写的throttles,上面注释里的是rest_framework自带的
'App.throttles.UserRateThrottle',
),
'DEFAULT_THROTTLE_RATES': {
# 5/m 一分钟5次限流
'user': '5/m',
}
}
测试
登录一个用户
访问
这里我们限流的是每分钟访问5次,我们访问6次试试
除了可以单独在节流文件里面控制节流,还可以在视图函数里面控制节流
视图
如上截图例,这样就对UserAPIView这个视图类进行了节流