DRF-Django rest framework
1. 基于jwt的多方式登陆
1. 需求分析
1. 登录方式
1. 手机号+密码
2. 用户名+密码
3. 邮箱+密码
2. 流程分析(post请求)
路由: 自动生成
视图类: ViewSet(ViewSetMixin, views.APIView)
序列化类:重写validate方法,在这里面对用户名和密码进行校验
3. 代码实现
如下.....
2. 代码实现
1. 路由
path('login/', views.LoginViewSet.as_view({'post':'create'})),
2. 视图
class LoginViewSet(ViewSet):
def create(self, request, *args, **kwargs):
ser = LoginSerializer(data=request.data)
ser.is_valid(raise_exception=True)
token = ser.context.get('token')
username = ser.context.get('username')
return APIResponse(token=token, username=username)
3. 序列化类
from rest_framework import serializers
from app01.models import UserInfo
import re
from rest_framework.exceptions import ValidationError
from rest_framework_jwt.utils import jwt_encode_handler, jwt_payload_handler
from rest_framework_jwt.views import obtain_jwt_token
class LoginSerializer(serializers.ModelSerializer):
username = serializers.CharField()
class Meta:
model = UserInfo
fields = ['username', 'password']
def validate(self, attrs):
username = attrs.get('username')
password = attrs.get('password')
if re.match('^1[3-9]\d{9}$', username):
user = UserInfo.objects.filter(phone=username).first()
elif re.match('^.+@.+$', username):
user = UserInfo.objects.filter(email=username).first()
else:
user = UserInfo.objects.filter(username=username).first()
if user and user.check_password(password):
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
self.context['token'] = token
self.context['username'] = user.username
return attrs
else:
raise ValidationError('用户名或密码错误')
2. 自定义user表 签发token 认证类
1. 表模型
class MyUser(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=32)
phone = models.CharField(max_length=32)
email = models.EmailField()
2. 路由
path('login2/', views.MyLoginView.as_view()),
3. 视图
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
from rest_framework_jwt.views import obtain_jwt_token
class MyLoginView(APIView):
def post(self, request, *args, **kwargs):
username = request.data.get('username')
password = request.data.get('password')
if re.match('^1[3-9]\d{9}$', username):
user = MyUser.objects.filter(phone=username).first()
elif re.match('^.+@.+$', username):
user = MyUser.objects.filter(email=username).first()
else:
user = MyUser.objects.filter(username=username).first()
if user and user.password == password:
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return APIResponse(token=token, username=user.username)
else:
return APIResponse(code=101, msg='用户名或密码错误')
3. book publish author表关系及抽象表建立
以后所有的数据删除,尽量用软删除,使用一个字段标志是否删除,而不是真正的从数据库中删除
1. 这样删除数据不会影响索引,不会导致索引失效
2. 之前存的用户数据还在,以备以后使用
class BaseModel(models.Model):
is_delete = models.BooleanField(default=False)
create_time = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
class Book(BaseModel):
name = models.CharField(max_length=16)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish = models.ForeignKey(to='Publish', db_constraint=False, on_delete=models.DO_NOTHING)
authors = models.ManyToManyField(to='Author', related_name='books', db_constraint=False)
@property
def publish_name(self):
return self.publish.name
@property
def author_list(self):
return [{'name': author.name, 'sex': author.get_sex_display()} for author in self.authors.all()]
class Publish(BaseModel):
name = models.CharField(max_length=16)
address = models.CharField(max_length=64)
class Author(BaseModel):
name = models.CharField(max_length=16)
sex = models.IntegerField(choices=[(0, '男'), (1, '女')], default=0)
class AuthorDetail(BaseModel):
mobile = models.CharField(max_length=11)
author = models.OneToOneField(to='Author', related_name='detail', db_constraint=False, on_delete=models.CASCADE)
1. book表 单增 群增
class BookView(APIView):
def post(self, request, *args, **kwargs):
if isinstance(request.data, dict):
ser = serializer.BookSerializer(data=request.data)
ser.is_valid(raise_exception=True)
ser.save()
return APIResponse(data=ser.data)
elif isinstance(request.data, list):
ser = serializer.BookSerializer(data=request.data, many=True)
print(type(ser))
ser.is_valid(raise_exception=True)
from rest_framework.serializers import ListSerializer
ser.save()
return APIResponse(msg='增加%s条成功' % len(request.data))
2. book表 单查 群查
class BookView(APIView):
def get(self, request, *args, **kwargs):
pk = kwargs.get('pk', None)
if pk:
book = models.Book.objects.get(id=pk, is_delete=False)
ser = serializer.BookSerializer(instance=book)
else:
book_list = models.Book.objects.all().filter(is_delete=False)
ser = serializer.BookSerializer(instance=book_list, many=True)
return APIResponse(data=ser.data)
3. book表 单改 群改
class BookView(APIView):
def put(self, request, *args, **kwargs):
pk = kwargs.get('pk', None)
if pk:
book = models.Book.objects.get(id=pk, is_delete=False)
ser = serializer.BookSerializer(instance=book, data=request.data)
ser.is_valid(raise_exception=True)
ser.save()
return APIResponse(msg='修改成功')
else:
from rest_framework.serializers import ListSerializer
pks = []
for item in request.data:
pks.append(item['id'])
item.pop('id')
print(request.data)
book_list = models.Book.objects.filter(id__in=pks, is_delete=False)
ser = serializer.BookSerializer(instance=book_list, data=request.data, many=True)
print(type(ser))
ser.is_valid(raise_exception=True)
ser.save()
return APIResponse(msg='修改%s条成功')
4. book表 单删 群删
class BookView(APIView):
def delete(self, request, *args, **kwargs):
pk = kwargs.get('pk', None)
pks = []
if pk:
pks.append(pk)
else:
pks = request.data
res = models.Book.objects.filter(id__in=pks).update(is_delete=True)
if res >= 1:
return APIResponse(msg='删除%s条成功' % res)
else:
return APIResponse(code=999, msg='没有要删除的数据')
5. 序列化类
from app01 import models
class ListBookSerializer(serializers.ListSerializer):
def update(self, instance, validated_data):
print(instance)
print(validated_data)
return [self.child.update(book, validated_data[i]) for i, book in enumerate(instance)]
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = models.Book
list_serializer_class=ListBookSerializer
fields = ['name', 'price', 'publish', 'authors', 'publish_name', 'author_list']
extra_kwargs = {
'publish': {'write_only': True},
'authors': {'write_only': True},
'publish_name': {'read_only': True},
'author_list': {'read_only': True},
}
6. 路由
path('books/', views.BookView.as_view()),
re_path('books/(?P<pk>\d+)', views.BookView.as_view()),
拓展
自定义token的签发和认证:https://www.cnblogs.com/liuqingzheng/articles/9766397.html